7 ms·
Upvoted not because I agree, but genuinely want to read discussion on this. I used to agree, when I first started doing Android development and "relearned" Java
by cellis 5y ago
Upvoted not because I agree, but genuinely want to read discussion on this. I used to agree, when I first started doing Android development and "relearned" Java since playing with Applets at age 14, but threading made me seriously reconsider. These days I make a living writing TypeScript ( nearly exclusively ), and although the tsc says it works, I always have a suspicion it could not work. Whereas with Java if it compiles it definitely works unless you have some R build issue. I think TypeScript is a nice middle ground, but I do wish there were some lower level semantics for backend TypeScript development. I've looked into Rust and it looks very complex and unfriendly ( I would need to rewrite nearly my entire backend libraries e.g. db drivers and ORM generators ). Anyway, it's a decent take, but I wish the same could be said of TypeScript.
- dmitryminkovsky 5y ago> and although the tsc _says it works_, I always have a suspicion it could _not work_ TypeScript fails me almost exclusively due to `!`. The association is so strong that whenever I encounter an error, I am excited to see if it's due to `!`. In the absence of non-null type assertions, TS feels very safe to me, largely due to experience of not seeing it fail.
- dtech 5y agoThrow in an eslint rule to disallow ! outside of tests, you won't regret it
- dmitryminkovsky 5y agoUnfortunately I have some spots where it’s unavoidable due to generated types that I can’t control being not quite right. It’s sad! Yes, otherwise I’d never use it, or far more sparingly (sometimes it is “correct”, though with effort it can be avoided)
- renke1 5y agoI have a utility function that I use for cases where I know for sure that a value is defined: export function assertIsDefined<V>( value: V, buildMessage = defaultAssertIsDefinedMessage ): asserts value is NonNullable<V> { if (value === undefined || value === null) { throw new Error(buildMessage(value)); } } It would prevent follow up errors if the value in fact was not defined.
- dmitryminkovsky 5y agoYeah I could definitely do this, and maybe should. But the issue is so systemic due to the bad generated types that this would cloud the code without much added benefit.
- renke1 5y agoI had my own share of problems with generated code, so I feel you. I often use that utility when I have some type where under certain condition a value will always be defined, but a union type would make it too complex to be useful.
- dmitryminkovsky 5y agoYeah in my case I am using Postgres via Hasura, which exposes the Postgres DB via a GraphQL API, which in turn can be used to generate types. Unfortunately the nullability of fields in a Postgres view cannot be determined, so all fields in the corresponding types are nullable [0], even if they aren’t in the actual underlying table. So I end up using ! a lot because I know the field is non null in Postgres. It’s a unfortunate. [0] https://github.com/hasura/graphql-engine/issues/1965 https://github.com/hasura/graphql-engine/issues/1965
- jraph 5y agoWhat do you mean, could you explain / give an example?
- dmitryminkovsky 5y agoTypeScript has the ! operator [0], which can be used to override the type system’s null check. For example, suppose I have a variable of type type Name = string | null const name : Name = null and I pass it to a function that expects just a string (not null), function len(str: string) { return str.length; } Then len(name); will fail type checking, but len(name!); will not fail type checking, but will fail at runtime. [0] https://stackoverflow.com/questions/38874928/operator-in-typescript-after-object-method https://stackoverflow.com/questions/38874928/operator-in-typ...
- 8note 5y agoOh wow, I did not know that this existed. Definitely gonna need a linter to make sure it's never used. Do you know why it was added? Ive used an annotation that disables type checking on a couple unit tests, but this seems much harder to notice
- dmitryminkovsky 5y agoDefinitely not a TS expert but I think it’s for cases where you know something “better” than it is known to the type system. An example that pops to mind is how React’s createContext() typings for some reason require a non-bill default value, but you may not have such a value at the time the call is made. Personally I think it’s totally legit to just do createContext<T>(null!). I don’t think this leads to errors that won’t get quickly noticed. But if you get carried away, it’ll bite you for sure, especially in code that has more going on than define a React context.
- TranquilMarmot 5y agoI write TypeScript every day, and sometimes it can be pretty useful. Like, if you have an interface... interface MyInterface { someValue?: string; /** Let's say this only exists if `someValue` exists */ someOtherValue?: string; } And then in some code later... const myFunction = (someParam: MyInterface) => { if (someParam.someValue) { myOtherFunction(someParam); } } // let's say this function is only EVER called if `someValue` exists // we know more than the type checker in this case const myOtherFunction = (someParam: MyInterface) => { console.log(someParam.someValue!.length); console.log(someParam.someOtherValue!.length); } There are definitely more "correct" ways to do this (i.e. using `Partial` or re-casting to another type) but sometimes there are edge cases that aren't worth doing things more correctly (like, if this is only happening in one spot) Lots of folks make the mistake of assuming the TypeScript is strongly typed, but it's not really... I like to think of its type system as "squishy" in that you can very very easily fake things or trick it into compiling. I think of the types more as comments and hints about the code and not there to ensure program correctness. This is actually one of my favorite features of TypeScript; it's not as strict as, say, Java or Scala, and it lets you get away with some things without having to rework all of your types. This can be a bit of a footgun, BUT if you're also writing unit tests and integration tests then you'll have all of your bases covered.
- void_mint 5y agoYou may already know, but C#/.NET and TypeScript are closely related and C#/.NET gets a lot of praise for building kind of a more ergonomic Java. It might be worth checking out if you enjoy TypeScript and also Java. FWIW they've come far from the "Microsoft means Windows development" era of C#, if that's a concern of yours.
- chromanoid 5y agoI agree. I am very curious how the .NET environment develops. The CLR is much more embeddable. Unity3D chose C# for a reason. Blazor is another interesting promising .NET technology. Considering Microsoft's engagement in Open Source I can imagine they are able to overtake the role of Java in the long run.
- TranquilMarmot 5y agoI'll echo this sentiment; I did full-time C# development for work for two years and it was a dream. Nowadays I do a combo of Java and TypeScript and find myself constantly wishing I was just back in C# land where it takes the best bits of each language.
- mort96 5y ago> although the tsc says it works, I always have a suspicion it could not work. Whereas with Java if it compiles it definitely works unless you have some R build issue That's not true, right? AFAIK, the Java type system is broken and any type might silently be another type which doesn't support any of the methods the static type would indicate. It's basically as type safe as C in my eyes.
- mrkeen 5y agoIt's not that bad. Sure I'd call parts of it broken, but this isn't it: > any type might silently be another type which doesn't support any of the methods the static type would indicate When an object is typed differently from its actual runtime type, it's usually because it's hidden behind an interface type. So it indicates fewer methods than it supports. Safe, but unergonomic!
- twic 5y agoVariables being nullable is not "as type safe as C". Please don't waste people's time with hyperbole like this.
- mort96 5y agoI don't see why not? In Java, every access of an object variable can blow up your program even though the type checker is happy. In C, every access of a pointer variable can blow up your program. This seems very similar. Neither language provides type safety. EDIT: To be clear, Java is definitely safer than C. When Java "blows up" due to a null variable access, it throws an exception in a well-defined way. When C blows up due to a null pointer dereference, anything can happen, and if you're lucky your program terminates unconditionally. It's just that neither error is caught by the type system.
- edem 5y agoYou should take a look at Kotlin then. I'm surprised that no one mentioned this so far.
- lmm 5y agoYou might like Scala - it's a first-class backend language but also has a great development experience on the frontend (better than TypeScript in some ways) via Scala.js.
- throwaway4good 5y agoI read the point of the article more in terms of "one language for everything" rather than something about Java in particular. I think it is a fair point. Staying within a language and an eco-system of libraries, tools etec. makes sense so you can get profiency and just know how things work without too much thinking about it. However it only holds to an extent as many languages are tied to or are native to a particular platform. I.e. JavaScript in a web browser, Java on the JVM, Java in Android, Objective-C in iOS etc. And some are definately not mature when you go outside their habitat. Try to compile Java into JavaScript (using GWT or whatever), or into a binary. You can do it however it doesn't really makes sense, so much of a language is really its libraries and way doing things. You are not going to get HSQLDB and JPA running inside a web browser for any reasonable application.
- GoblinSlayer 5y agoYou don't need to run literally everything in the browser, we had web applications since the invention of CGI.
- occz 5y agoTry Kotlin! Android development had become much better for having moved to Kotlin, and I prefer it to Java for backend development as well.