9 ms·
Crystal's appeal, for me at least, is the productivity of Ruby with the memory efficiency and execution speed of C++. Static typing is just a way of achieving t
by Doctor_Fegg 6y ago
Crystal's appeal, for me at least, is the productivity of Ruby with the memory efficiency and execution speed of C++. Static typing is just a way of achieving that, it's not something I'm seeking per se.
- straight-shoota 6y agoRemember static typing is also really useful for code quality and avoiding hidden bugs. Some code in Ruby requires a ton of specs to discover bugs caused by type issues, while the Crystal compiler tells you immediately that something doesn't work out. I love Crystal's type system really for productivity reasons.
- sjwright 6y agoI haven’t ever understood the argument against static typing. I’ve never declared a variable and not simultaneously thought “this is going to be a float, always a float, never not a float.” The only exception to this is untrusted input, but for that an string is usually always fine.
- pansa2 6y ago> I’ve never declared a variable and not simultaneously thought “this is going to be a float, always a float, never not a float.” Never written generic/template code? Making that much easier is one of the main benefits of dynamic typing.
- viraptor 6y agoChange it to "this variable is always going to be a T, never not a T" and it still stands.
- sjwright 6y agoIt's possible—nay likely—that I don't understand the true value of generics. It's something that I've looked into on occasion and it never seemed all that useful to me. Most examples I've come across in the past were C++ and seemed like formalised workarounds for deficiencies in the C++ type system rather than being actually useful. I'm sure I've failed to grok them—or based on the code I write I'm not the target audience for them. I have no problem when a language allows the programmer to explicitly opt for a variable to be an undefined/dynamic type, whether as part of generics or as part of a defensive ingest of untrusted data. I admit this is previously unspecified nuance but in my mind this doesn't break my rule: "this variable is always going to be a dynamic type, never not a dynamic type." This means you know when to interact with it defensively. The thing I'd like in a hybrid static-dynamic language is type assertion blocks which restore some benefits of static typing while dealing with dynamic typed variables. E.g.: declare x as dynamic; x = untrusted_source(); if (x IS_A string) { // Inside here, x behaves as a statically typed string. // The compiler knows it and checks types appropriately. // Passing x elsewhere will send a static typed string. function_that_demands_a_string(x); } else if (x CAN_SAFELY_BECOME_A uint) { // True for any non-negative integer regardless of data type. // Inside here, x is always a statically typed uint. // If it was some other type, it was converted for me. } (This probably already exists in some language somewhere but my familiarity with languages is narrow.)
- ezrast 6y agoCrystal does some of what you want: https://tio.run/##ZVDBbsIwDL33KywmrRcaUXbbhHbeaYdpJ4RQaA1kCkllO6Ps57skBalshyQv7z3bT27owqLtMLS4h@CEAgu2W/aBGiwA1vEAzDSwkHGH2Tz/63p812VfzqG8pOun3IxkVS8Wqo5wo1ifOosFurYoGquZ4X33hY1EMc0TumzFb8PTMhcSSiAHjDZFsRjtCStC7rxrOXpf4XlSsMODcRndFau7ntwEvHqSmGEKNN45Wr1QYk7I0PpI97D6twk1iRotjWaEPoLzER185NXkxl0Qhl6FLjlu@uebk2ucUYfHCuolwEOMdwhWE1RA2nBM4B34b6S99eeXZDMMckQ4k@66OASixsa7W@s/u9kbYpkGuRFoGae83vFkAcPwCw https://tio.run/##ZVDBbsIwDL33KywmrRcaUXbbhHbeaYdpJ4RQaA1kCk... Note how the language is pretty smart about flow-typing variables as you narrow down their types. `x` here is typed as a tagged union (String | Int32 | Array(Char) | Float64 | UInt32), but by the time the program gets to the final `else` the compiler has figured out that the String and Array cases have already been dealt with (even though we never mentioned Array by name, just asked if the object implements a method that only Array implements), so it lets us call `x.abs`, which only works for numeric types. Of course, `abs` has different implementations for Int32 and Float64, but the signatures are compatible so the compiler lets it fly, resorting to dynamic dispatch at runtime. The missing part is that there's nothing like a CAN_SAFELY_BECOME_A operator so I had to implement that test myself (as `try_to_u32`) and call it early to get the flow typing to work. The Wikipedia article for the concept is https://en.wikipedia.org/wiki/Flow-sensitive_typing https://en.wikipedia.org/wiki/Flow-sensitive_typing
- sjwright 6y agoThat's very cool. And especially thanks for surfacing the Wikipedia article.
- dragonwriter 6y agoPython typecheckers (both pyright and mypy, I believe) do this (isinstance checks and some other checks in conditionals narrow the type on the defended path.)
- mekkkkkk 6y agoThe main benefit of generics is to easily maintain strong type information for implementers. With a <T>createMapWithStringKey(T arg) -> Map<string, T> You can keep strong type info with AType a var b = createMapWithStringKey<AType>(a) // b is for certain a Map<string, AType>
- ncmncm 6y agoIf all you get from static typing is runtime performance and correctness, your type system is not pulling its weight. In any serious statically-typed language, the type system does real heavy lifting. In practice that means that libraries execute code at compile time that, in effect, generate the code you would otherwise need to write (again) yourself. C, Pascal, and Go are examples of statically typed languages whose type system does only trivial work.
- onlyrealcuzzo 6y agoIs static typing really necessary for speed? The fastest JavaScript engines and LuaJIT are closer in speed to Crystal than Crystal is to C. Granted - all these languages are really fast - and unless you're doing something INSANELY performance dependent and you REALLY know what you're doing - I think familiarity trumps all. You're almost certainly going to write faster Crystal code if you're a Crystal expert than you would write C, C++, or Rust.
- viraptor 6y agoIt's not necessary strictly speaking, but it make things MUCH easier. JS in v8 has 3 (4?) layers of compilers already and each time some type changes at runtime you're taking a hit to go back to the interpreted version while functions jit compile again. There's a crazy amount of engineering effort that has to counteract a missing "this has one parameter and it's either a string or a float" annotation. In practice if you don't have a world class well funded team - yes, static typing is necessary for performance.
- socialdemocrat 6y agoThat is because JS was not built for JIT compilation. With a dynamic language like Julia built for JIT compilation from the very start you get both much simpler and cleaner design and higher performance. It uses a method JIT so it is deterministic and easy to analyze unlike JavaScript. You can lookup ahead of time how each function will get compiled with given input types.
- viraptor 6y agoI'm not sure what you mean by this. Why do you think Julia was made for JIT from the beginning? You can't analyse functions like this ahead of time: function foo(x) x + y end You've got an Any type interacting with an Any global. There's no better answer than you'd get from JS analysis.
- eigenspace 6y ago
- socialdemocrat 6y agoAs an old Ruby fan, you should seriously check out Julia. It had a lot of the same meta programming goodies as Ruby but with performance that often rivals C/C++. Actually I think Julia will frequently pull off being faster. It is crazy how good JIT compilation works today with a language specifically designed designed for it.