6 ms·
They are problems type systems are intended to solve: It just happens that Java's is too weak to deal with it well: They best you can do is use an option type,
by hibikir 10y ago
They are problems type systems are intended to solve: It just happens that Java's is too weak to deal with it well: They best you can do is use an option type, but even then, Java's Option type is far weaker than in other languages. Languages where null doesn't exist are far nicer.
Java's boilerplate comes from lacking type inference and from having a type system that is too weak, not one that is too strong: I'd argue that people's love for dynamic languages without type systems is cause by how people's idea of what types are, and what they do for you, come from Java and old C++, as opposed to something more powerful.
- jay-anderson 10y agohttp://types.cs.washington.edu/checker-framework/ http://types.cs.washington.edu/checker-framework/ - there is work going on in the java world to deal with nulls in the type system.
- twblalock 10y agoNulls are not a problem type systems are intended to solve -- they are a feature of type systems that was created on purpose. You might not like them, but that doesn't mean they constitute an oversight or omission on the part of the designers of the type system -- they wanted them there. They are useful. Many people misunderstand the option type in Java. It was created to make stream processing easier. It was not intended for general use, as in other languages. Regarding illegal arguments, they are unavoidable in any type system. Suppose you defined a function that splits a string into an array of n-grams, to which you pass the string as well as int n. If you pass an n which is greater than the length of the string, no type system will help you figure out what to do. It's just an invalid/illegal argument, and you will either have to decide what to return for that case (maybe an empty array, or even... null), or throw some kind of exception.
- Decade 10y agoThe inventor of the null pointer considers them to be a mistake: https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare https://www.infoq.com/presentations/Null-References-The-Bill...
- twblalock 10y agoSo what? He's wrong.
- meddlepal 10y agoThat quote gets pulled out of thin air every time this argument comes up and it's pretty silly. I think more specifically, nullable by default might have been the bigger mistake not that null is inherently a mistake.
- twblalock 10y agoThe fact that most of these replies mention esoteric langiages that have no traction in industry kind of proves my point.
- junke 10y agoThe mistake is Null being a member of all (reference) types. This is not the case in all languages that have a nil value. In Common Lisp if you declare an argument to be a string, it is an error to pass NIL. You have to declare the type to be "(or string null)". That's exactly what the Option type provides.
- twblalock 10y agoThat is not how Lisp works. You are just wrong.
- deleted 10y ago[deleted]
- junke 10y ago> That is not how Lisp works. You are just wrong. Please tell me how it works, then. I guess you could easily find a counter-example. First things first. Optional arguments are handled by &OPTIONAL and &KEY parameters, which can be used to provide defaults values as well as a flag indicating whether the argument is provided. The most used default value is probably NIL. NIL belongs to the SYMBOL, NULL, LIST and BOOLEAN types and their supertypes (ATOM, SEQUENCE, T). If you really want, you can include it in a custom type too. For most uses, the type (OR NULL U) is regarded generally as an optional U. This is consistent with the definition of generalized boolean and lists (a list is an optional cons-cell). If some corner cases, you have to use another sentinel value or use the third binding in &OPTIONAL and &KEY argument bindings. This is hardly a problem if you have a type U such as (TYPEP NIL U), but for most useful cases, (TYPEP NIL U) in fact returns NIL. Here below I define a function FOO which accepts a string and prints it: (defun foo (x) (print x)) The type declaration for FOO is: (declaim (ftype (function (string) t) foo)) In Java, such a function will works with null too, because null is an acceptable value for String. In Common Lisp, you have to write this declaration to allow NIL: (declaim (ftype (function (or null string) t) bar)) And just to test how it behaves, let's use IGNORE-ERRORS to catch errors and return them as secondary values. Calling the first FOO with NIL signals an error: (ignore-errors (foo nil)) NIL #<TYPE-ERROR expected-type: STRING datum: NIL> ;; Does not print anything else The same test case with the second FOO shows that it accepts NIL: (ignore-errors (foo nil)) NIL ;; prints "NIL" Lisp being Lisp, those checks are likely to be done dynamically, but in some cases, your compiler can determine if a variable will hold NIL and warn you about a conflicting usage. However, how type checks are enforced does not change the argument, namely that NIL is not an appropriate value for all types.
- jestar_jokin 10y agoRegarding nulls, have a look at how Haskell deals with nulls. The basic idea is that any nullable value gets wrapped in a "Maybe", and you use pattern matching to handle the case of missing/empty values. This is much more explicit than null values in Java, where any object could be null at any time, and actually leads to cleaner code (i.e. to avoid lots of "Maybe" boilerplate, you can match for "Nothing" and return a default value as soon as possible to first matching "Nothing"). Regarding illegal arguments, have a look at something like Idris, which has a type system with "dependent types". The Wikipedia page has an example[0]; types can have values, so you can express a "pairAdd" function that accepts two vectors, each vector requiring the same length. I guess "types" and "compile-time checks" are sometimes used interchangeably. I absolutely think tools (such as compilers) should be leveraged to provide as much assistance as possible; whether that comes in the form of types, or some other mechanism that resembles types. [0] https://en.wikipedia.org/wiki/Idris_(programming_language)#Dependent_types https://en.wikipedia.org/wiki/Idris_(programming_language)#D...
- twblalock 10y agoHow would Idris provide a solution to the situation in my example?
- jestar_jokin 10y agoWell, I don't know Idris in detail, so you're better off reading the wiki page I linked to, but I will try to explain further. Idris allows you define types whose definition depends on a value - these are called "dependent types". This allows you to define a type such as "a pair of integers, where the second integer is greater than the first". So, in your example, you could define an immutable String type that stores its length as a fixed value. Then, you define a function that accepts a String of length "len", and a Num (or Integer) with a value that must be less than "len". The type signature might look something like this (if I understand the syntax correctly): ngram : String len val => Num (a <= len) => Vect Num String
- twblalock 10y ago