One thing that comes to mind is Ruby's macro-style methods:
class BankAccount < Account
attr_accessor :balance
belongs_to :customer
end
What's something your favorite language has that others don't? Or something from a language you tried out that one time and immediately missed it in other languages?
Oldest comments (32)
Elm's claim-to-fame type inference is pretty wonderful
elm-lang.org/blog/compilers-as-ass...
The thing not mentioned that is really the key to this equation is that end-user Elm code cannot perform side effects. So all the code you write in Elm is purely calculation. Combined with the ML-family type system, you almost have to do it on purpose to crash Elm. I've found a case or two that will unexpectedly crash it (e.g. using a HTML attribute with a blank name and value), but caught it right away in dev.
I only mention it because the same type inference is available in other languages (Reason, F#, OCaml). But these languages cannot make the same guarantee since side effects are permitted. This is a pragmatic choice for them, because they are general purpose languages. It is an outstanding wish of mine to be able to mark specific code in F# as side-effect-free and have the compiler enforce that, in case my own discipline slips.
Yes. If anything this has kept me from adopting Elm for real even though I'm fairly enamored by it.
I've always sort of relied on the escape hatch you don't get it Elm. I'm much more used to programming in the chaos of Ruby. 🙃
Some day though. Some day, I'll find the discipline to stick to something like Elm.
It seems more limiting than it is in practice. But I can imagine Ports (the JS interop) being a pain if you need to integrate a lot of existing JS libraries. They closed the more direct escape hatch (aka native, kernel) in 0.19. And yeah, I have the sentiment that things are a bit too rigidly prescriptive in Elm-land. But it taught me a lot -- especially the depth of what you can do with just calculation. It's hard to go back to anything else after that, because pure calculations are so refactorable and testable. We are trialing Fable-Elmish, which is basically Elm with opt-in side effects. It is written in F#, which is syntactically close to Elm. I even have a strategy for isolating side effects to be able to keep the rest of the code pure.
If that's the case, I would suggest looking into PureScript. I dabbled in Elm a while ago and I really liked it, but I felt that the language had way too many opinions built into it, because it's actually a language and a framework.
PureScript is very similar to Elm, it's also heavily inspired by Haskell, has type inference, and compiles down to Javascript. However, it doesn't have a strict architecture built in and the interoperability with Javascript is a bit more straightforward.
I've been toying with PureScript for a couple of weeks now and, honestly, I'm not sure I'll ever go back to Elm. Plus, you can use PureScript for backend code too.
Thanks for the suggestion. I’ve been meaning to try it, but it’s philosophical closeness to Haskell gives me pause.
Oh, hey! I meant to reply to Ben, but apparently we wrote at the same time and you won 😅
Still, if you're familiar with Elm it shouldn't be hard to get the hang of it.
I don't know if I miss them all the time, but dependent types (found in Idris, among other languages) are very interesting. Learning Idris definitely had an influence on how I think about certain problems; for example, at work I needed to write some code to partition items in a user's cart into separate shipments. A post-condition of this code is that the total number of items across all of the returned shipments should be the same as the total number of items in the user's cart; in most languages, you would use rigorous testing to assert you'd done this, but in Idris, you can express this property in the type system itself!
Something I miss more often (also found in Idris, along with other ML-family languages) is type-directed search. If you don't know the name of a function, but you can describe what it does in a type, you can use that type to find the function you need. For example, let's say we don't know how to append vectors in Idris (vectors are like lists in other functional languages, only their length is part of their type). You can think of the type of append as being "take a vector of length N containing items of type A, and a vector of length M containing items of type A, and return a vector of length (N + M) containing items of type A". So we ask Idris to find such a function for us:
...and it gives us the answer!
Smalltalk has something similar in its method finder; we can ask it "which messages can I send to
'foo'
that return'FOO'
, and it'll tell usasUppercase
will do this for us.A random wacky feature in Scheme that I can't say I think about a lot (other than being just plain interesting and mind-bending) is continuations; they could merit their own post, but continuations are a way of encapsulating the "next step" a program would take. I recommend reading the Wikipedia article if that piqued your curiosity!
Two things I think are really powerful in F# that are not found in most languages.
Union types are a way to represent one of multiple different possibilities. It is a bit like an enum type that can have extra data with it.
Most languages have a way you can kinda-sorta define these. One common method in OO is an abstract base class with shallow inheritance. But it is a lot of code overhead versus the concise definition above. And it is also not particularly idiomatic to OO. People probably wouldn't bat an eye at using
case
on an enum, but type checking for a derived class is often considered a code smell.You can also represent these choices as nullable fields in a single class, but then you have to write a bit of code to control access and protect against the case where none or multiple of them are set at once. Doable, but annoying enough that people usually don't.
Value equality by default is very nice for testing. It means I can do things like this:
If the
actual
has the same values asexpected
(1 and "One" here), then it will return true. And it works for union types too. In most languages, these things have reference equality by default. So the last line would only return true ifactual
andexpected
were pointing to the same memory location, which is not super helpful. You can usually get value equality in any language, but it might be a pain. In C# for example, you can override the default implementations ofGetHashCode
andEquals
to get value equality. It adds an extra 8+ lines of code to every class definition (and each field adds more lines of code potentially). I believe a lot of people use tools to add them in automatically and then code folding to hide them. Or just manually check for equality when needed.And I could go on: no nulls, immutability by default, pattern matching, composable asyncs, sequences, etc. Then I need to go fix something in our VB code base, and it's 😬😬😬. Well, one thing VB has that most others don't is XML literals. So there's that.
I don't like when languages call abstract data types "union". Because it is technically not true. They are disjoint unions, which makes them nice to use. The only language that I know that has actual union types is typescript.
F# calls them discriminated unions, technically. For the purposes of my comment I called them union types to keep it conceptually simple. The extra adjective "disjoint" or "discriminated" is more technically correct, but for many people it automatically biases them to react with "too complex; didn't read". When really it is a simple concept.
String interpolation.
Deterministic object destruction is probably my favorite feature of C++ that is found in only a select few other languages. When execution leaves a function or any other scope, be it regularly or through an exception, all local objects get destroyed and their destructors executed. Not eventually when a garbage connector feels like cleaning up some leftovers but immediately. This includes the automatic destruction of that class' member objects.
That means there's also no need for
finally
: cleaning up all those file handles, memory allocations and network sockets and painting the sky blue again is done automagically by the destructors of properly written filestreams, smart pointers, socket classes and temporary sky blackeners.Pattern matching as done in ML languages.
I think it's a much more elegant way to handle end conditions and special cases than
if
statements and it makes the code much easier to reason about.It is also awesome when used in conjunction with union types.
If I had ever understood lisp's macros I would probably mention them here too.
Pattern matching, really loved it when I came across it in Erlang. Should brush up on declarative languages
Python's list comprehensions! The syntax is super elegant, and they are really performant.
In JavaScript, to filter values, you would do something like this:
in Python, you would use a list comprehension
You can also transform all the elements in a list (similar to a map in JavaScript):
List comprehension is awesome!
Thanks for the nightmarish flashbacks! 😂😱
I miss Swift's strongly typed enums with associated values a lot in other languages (Go, Python etc.).
From the textbook:
Ahahahaha