5 ms·
So what might make dynamic languages easier to write in? I enjoy dynamic languages more because: * "double kilometerToMiles(double km) { return km / 1.6 }" her
by ozy 10y ago
So what might make dynamic languages easier to write in? I enjoy dynamic languages more because:
* "double kilometerToMiles(double km) { return km / 1.6 }" here the types are of really low value, yet I have to type them in.
* a mutable list of generic and variable arity event handlers. Really hard to specify as a type (most languages cannot do it). Really easy to use.
* co- and contravariance and lists, the math works exactly opposite of intuition.
* when you change your mind on the types/arity beyond what your IDE can follow, it is a lot of low value work
* if your test suite has 100% coverage of arguments/return-value and field usage, you have type checked your program.
If I am going to write down types, they better be of value to me. Like types that are null or non-null, or tainted (from the user) or non-tainted. Or two numbers that are kilometers vs miles. Or only accessible under a certain lock or other preconditions. And be flow sensitive (kotlin style null checks), not make me write even more code.
But if you are a dynamic language, do be strong typed (no "1" == 1). Also be dynamic in arity, that is (part-of) a type. Don't be handwavy scoped, lexical scoping is probably the only predictable way to do scoping. Fail fast, like prevent spelling mistakes for non existing field names for example. And allow this to work: "2 * Vector(10,10)".
And from that perspective there is still quite some room for improvement in all classes of languages, I suppose, and good that there is lot of movement and experiments today.
- lucian1900 10y agoWriting down the types isn't a necessary property of static type systems. In Haskell, F# or (OCa)ML, you almost never have to actually mention any types. I do agree that Java-style types aren't of much value. That catches few errors at significant cost.
- MrBuddyCasino 10y agoCatching logical errors is only one out of several things that static typing gives you. Incidentally, right now this is a few positions above this posting: https://news.ycombinator.com/item?id=12350063 https://news.ycombinator.com/item?id=12350063 Better IDE support, a kind of self-documentation and increased performance come to mind. I know there are counter-examples for each of these points, but the general trend cannot be denied.
- paulddraper 10y agoThe cost of non-Java-style types is compile time :)
- lmm 10y ago> * "double kilometerToMiles(double km) { return km / 1.6 }" here the types are of really low value, yet I have to type them in. You shouldn't have to, and you wouldn't in say Haskell. > a mutable list of generic and variable arity event handlers. Really hard to specify as a type (most languages cannot do it). Really easy to use. You want the handlers to have types corresponding to the events they handle, right? I.e. a labelled product/coproduct (similar to HList). They do exist. > * co- and contravariance and lists, the math works exactly opposite of intuition. I don't understand the claim here? > * when you change your mind on the types/arity beyond what your IDE can follow, it is a lot of low value work In a well-designed language most of your functions will be generic, and the parts you have to change should only be the parts that your change actually affects. Obv. this ideal is not fully achieved yet, but we keep getting better at it. > * if your test suite has 100% coverage of arguments/return-value and field usage, you have type checked your program. Not true. That one example works for a given function does not prove the type is correct for all arguments. As a trivial example you could define a function like "def f(i) = if(i == 1000) "blah" else i". Typechecking would catch that immediately, but to catch it through testing you'd have to test every possible integer as input.
- ozy 10y agoTo most commenters: Indeed static typing has advantages as well, I just didn't list them. And some languages solve certain "complaints" I had. I would suggest though, that comparing haskell to javascript, is almost like comparing a train with an offroad bike. Which you choose when is a discussion at a whole different level. As for the list of event handlers example. The point it is a trivial piece of code. Any jQuery plugin writer can do it. Yet the type math behind it is complex. Java cannot express it. Most languages cannot be generic in function arity so cannot express it. Spending time on it is not worth the trouble. And paying this penalty at API level, where ever user has to pay, is just a sin. Some discussion from the dartlang on covariant lists: https://www.dartlang.org/articles/design-decisions/why-dart-types#why-are-generics-covariant https://www.dartlang.org/articles/design-decisions/why-dart-... The test suite idea was incorrect. Even 100% code coverage will not do. But for "normal" code, add reasonable amount of coverage. And any production runtime type error will be really surprising. And even when it does happen, the fix is clear and quick. A personal feeling on this topic is that it is all tradeoffs. But it makes me really happy to see gradual typing gaining traction. So you can start on your offroad bike, but end on a well oiled train, where that is worth the tradeoff. So you don't have to choose up front. Perhaps when we can even get runtime guarantees on perf/object layout when the type checker is happy.
- kilotaras 10y ago> double kilometerToMiles(double km) { return km / 1.6 } But what if you could have `miles kilometersToMiles(kilometers km)`? Under the hood its the same old doubles but you would be able to catch errors such as the one that caused Surveyor failure [1]. e.g. Haskell has units[2] and dimensional[3] that allow you to do exactly that [1] https://en.wikipedia.org/wiki/Mars_Climate_Orbiter#Cause_of_failure https://en.wikipedia.org/wiki/Mars_Climate_Orbiter#Cause_of_... [2] https://github.com/goldfirere/units https://github.com/goldfirere/units [3] https://github.com/bjornbm/dimensional https://github.com/bjornbm/dimensional
- spriggan3 10y ago> * if your test suite has 100% coverage of arguments/return-value and field usage, you have type checked your program. The most horrible argument in favor dynamic typing in my opinion. Test suits shouldn't be about checking if a return value is of expected type, that's ridiculous. It's implementing a type checker manually. There are a lot of things statically typed languages can do to make types painless : - (global) type inference (Crystal does that) - co and contravariance, it is not limited to dynamically typed language - optional parameters - adhoc type declaration like in C# (ex {x:1,y:"a"} is a type). - contracts - pattern matching - generics - ect ... etc ... I just dislike dynamically typed languages. Even interpreted languages should be statically typed IMHO. Again, there are multiple ways to make statically typed language painless when it comes to types.
- ozy 10y ago> Test suits shouldn't be about checking if a return value is of expected type Indeed and so they don't have to. When you have reasonable code coverage, it is really surprising to encounter type issues in production. And they are the easiest mistakes to fix. But the point is, runtime checks happen implicitly as you run the code. So no "implementing a type checker" needed ... On the other hand my comment on when you get the equivalent of being fully type checked was incorrect. Even 100% code coverage will not guarantee it for some code. I like both kind of languages, and use both. While you get some advantages in static languages, you do also pay a price in language semantics and effort. It is good to point that out, so we can continue making progress, like Crystal or latest C# (and latest F#!). There used to be a time when the mood was: Java is good for all, stop confusing us with your new languages.
- naasking 10y ago> * if your test suite has 100% coverage of arguments/return-value and field usage, you have type checked your program. This is absolutely false. Others have pointed this out, but types are much more general than runtime checks in dynamically typed languages. For instance, you can check at compile-time that your program doesn't have data races or deadlocks: http://www-kb.is.s.u-tokyo.ac.jp/~koba/typical/ http://www-kb.is.s.u-tokyo.ac.jp/~koba/typical/ Or design a library in Haskell to ensure file handles and other scarce resources are promptly reclaimed: http://okmij.org/ftp/Haskell/regions.html#light-weight http://okmij.org/ftp/Haskell/regions.html#light-weight Neither of these are testable in dynamically typed languages. Static types are much more powerful than dynamic types, in general.
- marcosdumay 10y ago> "double kilometerToMiles(double km) { return km / 1.6 }" What about: toMiles (Kilometers k) = Miles (k/1.6) Then you do: let x = Kilometers 5 print (toMiles x) And, of course, any calculation will only accept the correct units. At this naive implementation, you'll have to add the conversions to satisfy the compiler, but there are Haskell libraries that bring automatic conversions too. Anyway: > Like types that are null or non-null, or tainted (from the user) or non-tainted. That's Haskell. > Or two numbers that are kilometers vs miles. That's my example up there. > Or only accessible under a certain lock or other preconditions. Yep, Haskell. > And be flow sensitive (kotlin style null checks), not make me write even more code. That's emulating what people do in Haskell.