HN2new | past | comments | ask | show | jobs | submitlogin
Language Design in the Real World (sigplan.org)
77 points by yeputons on May 21, 2022 | hide | past | favorite | 17 comments


Ceylon and Kotlin both came out in 2011 and neither was popular. I was hoping Ceylon would come out on top as giving the most without incurring the complexity of Scala (which can co-exist for other uses/users).

From Ceylon Wikipedia[0]

> Null safety

> Union and intersection types are used to provide null safety. The top type of the Ceylon type hierarchy is the class Anything, which has two subclasses: Object, the superclass of all normal classes and all interfaces, and Null, with the only instance null. Since Object and Null are disjoint types, most regular types like Integer or List<String> are not nullable; a nullable type is the union Integer|Null, abbreviated Integer?.

So not only do we get null safety, we get both intersection and union types. The emphasis on immutability is also a great selling feature, but perhaps that limited its interoperability with Java collections and adoption.

[0] https://en.wikipedia.org/wiki/Ceylon_(programming_language)


Is there a language for the JVM with union types that's gaining any popularity? [Edit: Scala 3+ any others?]

TypeScript is a bit of an outlier in this respect of being widely adopted with this particularly useful feature. Null-safety is basically a corner case of union types.


> Why has no one done this before Kotlin?

...in reference to nullable types being added

1. Languages generally release with this (ie Swift, PHP), rather than add it later

2. There is a risk that it won't be accepted because of bad assumptions that can either be technical or social. ie This feature exists and is criticized in other languages like PHP

3. There is no proof that it's any more important than any other feature being discussed.

4. There is work associated with doing it.

There ya go.


Eiffel is one example of a language that added nullable types after initial release, still during the late 90's.


> Languages generally release with this (ie Swift, PHP), rather than add it later

PHP did not get nullable types until 7.1 [0]. Function arguments (only) supported it in PHP 5 with the syntax `function(stdClass $arg = null)` but I would hardly call that nullable type support.

[0]: https://www.php.net/manual/en/migration71.new-features.php


Can someone explain to me why nullable is even desirable (vs something like optional)?


Philosophical bits aside, it's worth noting that in Kotlin, nullable values have somewhat similar operators as Maybe/Option types in other languages

There's safe-access "?." and ".let", which only fires if the receiver is non-nullable

  api.getUser(1)?.let { user -> println("user was not null") }


Nullable has the nice feature of the hardware detecting when a program tries to dereference it. It's a cost free `assert()`.

My unpopular opinion is that null pointers are unfairly maligned.


That requires protected memory and zero isn’t unique in that. The OS could make many more addresses special in that respect.

On most (¿all?) OSes it also won’t work if you make your structure large enough, and try to access a field at an offset (let’s say your OS makes the first 4kB of memory unaccessible by user code, you declare p as a pointer to an array of a million integers, but don’t initialize it and then access p[999999])

It also is an implementation detail. A compiler could compile something like Either[Foo,Null] (with Foo a type and Null a value or a type that’s guaranteed to have only one instantiation) to either a pointer to a Foo or a null bit pattern.

Even better, an implementation _could_ hide the “it’s not a Foo” bit in any unused bit inside a Foo object (say inside padding, or in a byte storing an enumeration that has less than 256 values)

(aside: are there languages that represent Either[FooPtr,BarPtr] as a pointer-sized field holding either a pointer to a Foo or one plus a pointer to a Bar, using the fact that top bits of pointers to objects always are zero to discriminate between the two?)


> That requires protected memory

I know. I was so happy to see real mode DOS go away.

> an implementation _could_ hide the “it’s not a Foo” bit in any unused bit

Yes, it could. But it requires extra instructions to check it. Null gets checked for free (no extra instructions or time) by the hardware. A seg fault isn't any more dangerous than an assert failure.


Memory tagging (the hardware checks certain bits of a pointer, not just if it's null) is becoming more and more common in the non-X86 world.


nullable pointers can take up the same amount of memory at runtime, vs optionals that can be nested, so you need to represent .none from .some(.none), which means you need at least another bit


Has nobody done this before Kotlin?

Most languages including Java and C++ have “non-null” and “nullable” annotations. These types work exactly like Kotlin’s afaik, where if they’re not specified the compiler is flexible and assumes whatever works.

In fact Swift and C# seem to have this same feature or at least something similar. And I know C# added it way before Kotlin.


> Most languages including Java and C++ have “non-null” and “nullable” annotations

I thought this too until I gave them a try 6 or 7 years ago. And nope, it was just advisory in the Java case. May as well have been a comment. At best, it's shorthand for: throw a runtime exception if-and-only-if this method was called (directly) by Spring-or-similar.

What would a variable marked with Nullable mean anyway? That the other variables are not nullable?


That is what happens when CI/CD engineering teams don't place the right tooling into the pipeline, otherwise it stops being advisory.


What is the right tooling?


SonarQube, PMD, SpotBugs among others.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: