
Ask HN: Great programming language features, other languages should steal? - manx
You cannot be fluent in all programming languages. But this also makes you blind for language features a particular language really got right, or killer libraries that are just amazing. Which are these widely unknown features, that you only get to know, when working with a language and its ecosystem?
Example: I&#x27;m coming from Scala. Starting to develop a Flutter app with Dart, made me realize how great and safe the serialization ecosystem in Scala is. You can serialize types (and type hierarchies) with a convenient syntax that is completely decoupled from the type itself, while high-performance serialization code is generated at compile-time via macros. Libraries include: https:&#x2F;&#x2F;circe.github.io&#x2F;circe&#x2F; https:&#x2F;&#x2F;github.com&#x2F;suzaku-io&#x2F;boopickle
======
deepaksurti
Common Lisp condition system

[1]
[https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node317.html](https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node317.html)

[2] [http://gigamonkeys.com/book/beyond-exception-handling-
condit...](http://gigamonkeys.com/book/beyond-exception-handling-conditions-
and-restarts.html)

------
dTal
It's more of a paradigm than a feature but, multiple dispatch à la Julia. One
of the creators of Julia makes a strong case that it is _the_ key to libraries
that "compose" without being aware of one another:

[https://www.youtube.com/watch?v=kc9HwsxE1OY](https://www.youtube.com/watch?v=kc9HwsxE1OY)

~~~
Foober223
They got that from lisp.

~~~
bjoli
Julia compensates for time lost by making a lot more use of it in the stdlib
than, say, most CL implementations do. It is as if the julia people saw it and
went "wow, this is good!" and had it in from the beginning. With their focus
on maths, it is hardly surprising.

~~~
eigenspace
There's actually a pretty fundamental reason that Julia's Base and stdlib
makes more use of multiple dispatch than Common Lisp (or any other language in
existence with multiple dispatch). It's that in basically every other
language, multiple dispatch comes with a non-neglible performance penalty.

Julia's multiple dispatch semantics were designed around having a JIT
compiler, and it's JIT compiler design was designed around having multiple
dispatch, and this tight integration let us be _really_ good at de-
virtualizing the dispatch, removing the hefty performance pentalty.

This is why even basic arithmetic operations like +, * and whatnot are able to
be generic functions (with a gigantic number of methods, 184 for + and 364 for
* currently just in Base and LinearAlgebra!) without any runtime performance
compromise.

By contrast, Nim for instance just removed multiple dispatch in their 1.0
release because nobody was using it due to being so slow.

~~~
bjoli
Thanks! I always suspected you could have a fast dynamic dispatch in a typed
language if you locked it down enough to not allow redefinitions at runtime
and such (which removes a lot of the fun of CLOS). It makes sense to let the
jit do the heavy lifting though!

~~~
eigenspace
Yes, Julia definitely had to make some dynamism restrictions that I suspect
would dismay some lispers, but it is still a quite dynamic language. The
language devs do some pretty clever things to have our cake and eat it too.

On the flip side, I think we have some dynamic metaprogramming magic of our
own that might even impress some lispers such as IRTools.jl's dynamos or
Cassette.jl's overdubing.

------
thehappypm
Every language should have robust, standard collections functions like Python
does. Once you start doing quick things with lists like the zip function, or
list comprehensions, it's hard to go back.

~~~
p0llard
> Once you start doing quick things with lists like the zip function, or list
> comprehensions, it's hard to go back.

Totally agree with you on this one, but I'm not sure I'd go so far as to say
that they're a defining feature of Python, more of functional languages, from
which Python has borrowed a thing or two.

~~~
thehappypm
Agreed! Python is just one example of a language that does it well.

------
dfalzone
This is pretty minor but I like how in Rust you can use constructs like if-
statements and match-statements as expressions. For example:

    
    
      let foo = if some_condition {
          "condition is true"
      } else {
          "condition is false"
      };
    
      let bar = match x {
          0 => "string",
          1 => "another string",
          _ => "default"
      };
    

It's not super significant but I think it's an elegant syntactic feature.

~~~
Foober223
They got that from lisp.

But in lisp it's more than just a syntax trick that only works for a few
predefined cases.

~~~
Jtsummers
And Algol and others. It's a nice feature when available, certainly my
preference. I find I can often write things more cleanly given an expression
oriented languages than ones dominated by statements.

------
ulam2
1\. Python's list slicing and indexing is the perfect mix of simplicity,
intuition and power. It is surprising how few languages have similar
implementations.

2\. Currying like in Haskell.

~~~
skrtskrt
Python list/set/dict comprehensions too

~~~
hansvm
And generator comprehensions -- it's especially nice that you can directly
write things like `sum(x*x for x in g)` without needing an extra set of
parentheses or allocating an intermediate collection.

------
verdverm
Golang, avoid this idea in the service of software engineering.

Go tries to be a syntax minimalist so that the writers can make what's there
the best rather than building the world of fancy new PL features. It also
means there are fewer days of doing the same thing and most people's code
looks the same. <\- this is such a difference maker

------
stakkur
Python data structure manipulation/comprehensions. I realize there's some
overlap with other languages, but this to me is Python's 'killer' feature.

------
jzoch
1\. Pattern matching with destructuring a la scala, rust, ocaml, etc.

2\. scoped threading a la kotlin and by using certain libraries, rust to a
degree.

3\. structs / records (i feel bad putting this since every language but java
seems to have it).

4\. macros of some kind

5\. type inference

6\. enums a la rust / sealed types in kotlin which are needed for pattern
matching afaik

------
didip
1\. I like Erlang's Supervisor. If Go's goroutine has a unique ID, I think it
can steal that design.

2\. There was one new language that I don't remember the name, its data
structures automatically turned to thread-safe upon concurrent access. That's
smart. I wish all languages do that. Less data structure names people have to
remember.

3\. The compiler can cross-compiles to many different architectures similar to
Go or Zig. This makes deployment story much simpler.

4\. The compiler produces single binary by default. This also makes deployment
story simpler.

5\. This is year 2020. Every language must have an event loop so that they can
have async I/O routines. Preferably in the form of CSP (green threads +
channels).

As you can see I care about the ergonomics and tooling outside the language
itself.

------
non-entity
I like how Erlang handles binary and bitstring data. Extremely useful if
you're doing any sort of protocol implementation.

~~~
Jtsummers
So many programs I've written would have been easier with Erlang's binaries
and pattern matching. A lot of what I've done has boiled down to parsing and
transforming binaries from one format to another. I've made a few POCs for
work in the past (that I couldn't have convinced them to use no matter what,
only C/C++/C#/Python were used) that demonstrated a much simpler version of
core program logic because of those two features. The code was often 1/10th
the size (if not smaller), clearer, and more extendable. And this wasn't just
because I was writing it for a second (or third) time. The code in the other
languages was good, clean code as well. It's just _harder_ in those languages
to express the same things as concisely.

------
warmind99
I really like the trait/struct/enum model of programming that you find in
Rust. I'm a quant and I do a lot of higher math, and the trait method of
programming is very very similar to how you might construct algebraic
structure in the set=>group=>field etc way.

------
ktm5j
I'm a big fan of scope guards in D:
[https://tour.dlang.org/tour/en/gems/scope-
guards](https://tour.dlang.org/tour/en/gems/scope-guards)

------
mrkeen
* Pattern matching with _totality checking_. Warn us if a cased is missed.

* Higher-kinded types. Can a List<Int> and a Stream<Int> both be considered a T<Int> ?

* Differentiate between functions with and without effects.

------
dbsmith83
Kotlin Extension Functions

[https://kotlinlang.org/docs/reference/extensions.html](https://kotlinlang.org/docs/reference/extensions.html)

I personally love it for when I have different data classes for different
layers of the application (REST objects vs. controller level objects vs.
Database objects) and need to convert between them. I simply just add an
extension to one layer's data object to convert it to the other layer's type

------
raja_mukherji
Goal-directed evaluation from Icon. Makes generators composable.

------
bjoli
R6rs scheme's (or even better Racket's) macro system. Recently similar systems
have been making their way into other languages, but the AST-like syntax of
lisps make it a fair bit easier to use.

Other than that? Delimited continuations. Guile-fibers, a parallel concurrent
ML (which I would describe as a generalisation of go's concurrency model) for
guile scheme is implemented using them as a scheme-only library. No low level
voodoo. Just straight forward scheme.

------
bjourne
Factor allows almost any special character in word (function) names. It is
incredibly useful when you get the hang of it. I would love to have it in
other languages.

E.g. is_prime(1234) => prime?(1234), append_inplace(l, e) => append!(l, e),
array_equal(a, b) => array=(a, b), midi_to_mp3(a) => midi>mp3(a),
reciprocal(a) => ^-1(a)

Lisp can do some of it but not "()" or (I think) "`';"

~~~
kazinator
In Common Lisp you can use pretty much any character in a symbol name, if you
escape it:

    
    
      [3]> '|(``"|
      |(``"|
      [4]> (defvar |(``"| 42)
      |(``"|
      [5]> |(``"|
      42
    

It's pretty dubious for code; it's useful when working with some data format
that has identifiers with its own validity rules.

There is more than one way to escape: vertical bars or backslashes:

    
    
      [6]> (eq '|(``"| '\(\`\`\")
      T

------
kmatthewc
Nullability built into the type system like Kotlin. one main difference
between kotlin optionals and swift options (for example) is that Kotlin
nullability is enforced during compile time.

I'm not aware of many languages which do that other than Kotlin.

------
MosheZada
JavaScript’s object destructuring

------
xinau
Golang's level of boringness. It's just boring enough to still be useful.
Often it's easy to understand random code and write "reasonable" code.

------
joshsyn
My ideal language is something like F# but with HKTs, trait, macros, union
types (without discriminator), basically most features dotty aka scala 3
introduced.

~~~
joshsyn
Its funny though, as I am personally switching to scala 3 for the features I
mentioned. I find the features particularly handy for building distributed
systems using Akka. And I wished they'd get tooling just right out of the bat.
(sbt doesn't seem great)

------
manu3000
algebraic data types and parametric polymorphism, so you can define an option
type for computations that fails and get rid of nulls

