Arguing that all `null`s should be replaced with `undefined`s in JS code also kind of implies to me that JSON should replace the `null` keyword with `undefined`, which just sounds crazy to me. Why store "undefined" values in serialized data? If it's not defined, don't define it... `null` allows you to convey that "this value may exist, but currently doesn't".
Plenty, though it depends a bit on what you count as JS standard library.
An object’s prototype may be null, so things like Object.getPrototypeOf(), Object.setPrototypeOf(), Object.create() and .__proto__ all deal with null.
Anything that is accessing a named property that exists on a class will yield null for no value, never undefined.
This is seen in DOM methods; things like Node.firstChild and Node.parentNode spring to mind as potentially null, and in each case it would be semantically quite wrong for them to be undefined—they are defined, as “no value”.
People should avoid using undefined, not avoid using null.
"this value was intentionally set to 'null'
in contrast to undefined:
'this value is undefined (e.g. was never [correctly] set)'
Though this doesn't apply to dealing with unsanitized json parsing.
For example, take Array.prototype.find(). Would be nice to have null here as a default return value. But what about Arrays containing null as a value? What about the case of null || false? What about the case of false || null?
There were a lot of design discussions to come up with those APIs...but I agree with you that technically, undefined should not exist. I'd rather have a syntax error being thrown than having to deal with undefined.
As undefined is specified as a hackaround as a global property, ... most of the implications are just a workaround, too.
A failing of JS lang that so many of these discussions have to keep happening.
document.getElementById("asdf") // returns null;
document.getElementsByTagName("asdf") // returns [];
document.getEleemntsByTagName("asdf")[0] // returns undefined
document.getElementsByTagName("body")[0].getAttribute("asdf") // returns null
//
document.getElementsByTagName("input") // assuming not empty for the next several lines
document.getElementsByTagName("input")[0] // Element object
document.getEleemntsByTagName("input")[0].value // returns "" as valus is implicitly an empty string if not supplied
document.getElementsByTagName("div")[0].value // returns undefined even though the element is present but expresses an inference to an unsupported property
I completely agree supporting both null and undefined complicates some forms of validation, but I have accounted for this in my test automation. I don't encounter this problem with input validation or managing event handlers.Here are the rules I use:
* undefined is a value where a value is never before assigned. Yes, you can do stupid things in opposition to the default such as arbitrarily assigning undefined or even redefining undefined to an assignment, but those footguns are not be accident.
* null is a value that is explicitly assigned.
If you program with those assumptions in mind you are safe 99% of the time given default language constructs, which doesn't account for the intentionally bad decisions other people make. This also helps with troubleshooting because when an error is encountered due to a null or undefined value the assignment distinction helps to diagnose the problem.
> document.getElementsByTagName
For what it's worth I usually wrap these functions to e.g. throw an error if they don't find any items as that's what you usually want to happen but forget to write checks for. It's rare I'll use getElementById and expect it not to find something.
Lots of undefined + null values crop up from situations like this where you want to fail when something you expect to be there isn't found e.g. file handling, dictionaries, web requests.
It's a no-brainer to use TypeScript as well if you want robustness from these kinds of bugs, where returning undefined or a value is more practical because TypeScript will force you to check for undefined. I don't understand why anyone would willingly give up to type checks like these as it's obvious to me you can't compete with automated checking.
As you said,
undefined == I just don’t know what the value is
null == I know that there isn’t supposed to be a value here.
const w = (fn, _) => function(...args){
return (_ = fn(...args)) === null ? undefined : _;
};
document.getElementById = w(document.getElementById.bind(document));Returning undefined for null, as well as changing dom functions is a great way to ensure unintended side effects will creep into your code.
foo
//Uncaught ReferenceError: foo is not defined
if not property access, and it lies o = { foo: undefined }
o.foo
//undefined
o.hasOwnProperty('foo')
//true
Array is an object, access by index is property access a = []
a[0]
//undefined
That's unfortunate. In Ruby: foo
#NameError (undefined local variable or method `foo' for main:Object)
defined?(foo)
#=> nil
o = Object.new
o.foo
#NoMethodError (undefined method `foo' for #<Object:0x000055f2f4e56e78>)
a = []
a[0]
#=> nil
And Ruby enforces method arity and keyword parameters: def foo(value)
end
foo
#ArgumentError (wrong number of arguments (given 0, expected 1))
def bar(value:)
end
bar
#ArgumentError (missing keyword: :value)
Basically it throws on undefined.I think reimplementation is a great way to uncover how things work, Ruby "fix" for property access
http://sergeykish.com/ruby-like-javascript-undefined.rb
Anyone knows how to relax arity?
For everything else, use false to “explicitly assign it”, you don’t need a third type.
Then you still have null, you’re just spelling it funny while confusing all the other developers who have to deal with your code and making it incompatible with language constructs like the nullish coalescing operator.
If the concept you are trying to express is “null”, then please use null to represent that instead of bringing in a poor substitute like an overloaded false.
But otherwise I just leave undefined to play the role of "this optional argument wasn't defined" and null for everything else. I like null because You have to specifically set something as null. I can run into undefined through typos and such. I dont think you can accidentally hit null.
P.s. This reminds me of the one time in Python I thought, "Damn I wish I had both undefined and None". I needed to know if a user was omitting an optional argument or passing an explicit None into it. Ie. This data is optional and the data might be "None". I ended up using kwargs which weakened my function as it nolonger described all the possible arguments.
Sounds like kindof like an Optional<Optional<Value>>. An optional is just a container of at most one element, so you could emulate that with a singleton list, having None mean not specified, [value] be value, and [None] be explicit lack of value.
Null is:
>> JSON.stringify({"foo": undefined});
"{}"
>> JSON.stringify({"foo": null});
"{\"foo\":null}"https://en.m.wikipedia.org/wiki/Option_type
If you are using TypeScript (TFA mentions it), fp-ts provides a good functional programming layer. Although if you aren't already familiar with functional programming it's going to be hard as the documentation is rather lacking.
Only in Javascript though. In Typescript this would be clear from the fact that the type has the property.
Of course Typescript is not Javascript, but nobody should use plain JS anymore.
So ‘class undefinedDivideByZero extends InvalidType’. Then just check if a value is an instance of InvalidType. Then you can create much more specific invalid types.
If you have to account for 3 anyway, might as well account for N, and then create more information rich types.
Is there a name for this pattern?
> but readability is poor when every error must be handled many times instead of implicitly returning to callers.
I should clarify that I'm only using these types for parsing and transformation pipelines and not as a general replacement for exception handling—in other words only in places where you'd have to already worry about undefineds, nulls, and NaNs.
So far just context dependent. If the target is csv, generally just “”. If JSON, one of the existing types. If DSL, a discrete term from a custom grammar.
But I'd just love to tear it down and start again.
For something that's supposed to be a universal programming language, it's got so much stuff like this that makes it so unfriendly to newbies.
what's another one?
That's just one example of things in JavaScript that are poorly named for people to guess what they do.
Automatically creating a variable (with global scope) if you attempt to use a variable that doesn't exist.
Semicolons are optional, except when they aren't.
== and === (at minimum they should be reversed)
Emscripten can produce js as well as wasm, so you can build both and deliver according to support.
For example, a couple years ago GraphQL specifically added support for the difference between undefined and null, and it was a good change. An optional field on an input type can be left off (in which case it is undefined) or it can be explicitly set to null. For a mutation, these have very different meanings: undefined means "don't update the property" while null means "update the property to null (which usually means 'delete')". These are very different things.
This thread, https://github.com/graphql/graphql-js/issues/133, is a good overview.
That is pretty humorous, null means make it undefined, so I guess false will need to mean make it null, and true can mean make it false?
The general problem is trying to get enough metadata directly into the language to manipulate it's own programs with such metadata. Of course this never works it just goes to an edge case so absurd that absurd syntax stays reserved for things with meta operations so they can work on most things yet not themselves or each other.
Let's say I have an object that represents an object in the DB, and one of the properties on that object represents an relationship to another entity which may not always be there. Then setting null on the object would mean set the corresponding DB column to null. How is that a discrepancy?
The problem with JS isn't that it doesn't really need null, it's that it doesn't really need undefined, but now that undefined is there it's impossible to rip it out. Most other languages that have null also have a separate concept of "doesn't exist": accessing a non-existent property would throw an exception, not return null, and for example you could tell the difference between whether a Map has a value at all vs has a null value by calling the equivalent of map.containsKey. Point is it is often necessary to tell the difference between "object doesn't have a property" vs. "property is null", and for better or worse (I think mostly worse) JS uses undefined to distinguish between those cases.
Maybe.
If there is an interface: `interface ISomething { x?: string };` and obj of this interface to have `obj.x = undefined` instead of `delete obj.x`.
Writing methods: `function x(param0, param1?, param2?) {}` to be used as `x(1, undefined, '2');` instead of creating the func as `function x(param0, option: { param1?, param2? })` and using as `x(1, { param2: '2' })`.
Returning undefined from a function: `function x(): undefined { return undefined; }`, instead of `function x(): void { return; }`.
Mixing the meanings of `undefined` and `null`, can bring a lot of troubles for JS devs when they use `Object.keys` or using `arguments` in function. IMHO If we keep that `undefined` means missing while `null` means no value, then we will have better JS code, using: `'x' in obj` instead of `obj.x === undefined` or `typeof obj.x === 'undefined'`, `delete obj.x` instead of `obj.x = undefined`, `obj.x = null` and then `obj.x === null` instead of `obj.x == null`.
> If there is an interface: `interface ISomething { x?: string };` and obj of this interface to have `obj.x = undefined` instead of `delete obj.x`.
In typescript additional properties are not a problem. Since it is using structural typing. In most cases spread and restructuring are better options for merging/overwriting and deleting. It is safer and easier to reason about.
> Writing methods: `function x(param0, param1?, param2?) {}` to be used as `x(1, undefined, '2');` instead of creating the func as `function x(param0, option: { param1?, param2? })` and using as `x(1, { param2: '2' })`.
I am not fan of creating functions taking options objects as argument. In many cases is better to create specialized functions
You have to know differences between those when coding in js/ts/flow. Ie. no 4. has implications when iterating ie. Object.keys({ foo: undefined }).length === 1.
Education around those - yes, but blacklisting null? Sounds a bit silly, however I agree that most developers overuse null when they actually mean undefined.
One example in code where null vs undefined can be used is sql.update(table, where, { foo: null, bar: 1 }) - meaning update foo to null vs sql.update(table, where, { foo: undefined, bar: 1 }) - where undefined means, don't do anything with that column. This helps a lot because it's much more verbose to conditionally construct object with a property or without it, however it's easy to set it defined/undefined.
If you use TypeScript and TSLint, there's also a rule for that: https://palantir.github.io/tslint/rules/no-null-keyword
It’s somewhat reassuring to see these comments here because at the time, I couldn’t deny that my solution isn’t ideal. At the same time, I know that favouring a less explicit approach to describing empty values is inevitably even more confusing - there has to be some way to indicate why something is empty. It’s still hard to program with a solution you know isn’t ideal... I really wanted a better answer or to find a better way forward with the reviewer, but in JS land it seems like an unfortunate but viable way to work.
All you need to do is use a condition like `v == null` or `v == undefined`. I like the first one more because it's shorter, but both are equivalent to `v === null || v === undefined`
And you can ignore the distinction then.
*Edit - recursive rather than no-op, to make it do something that people might abuse.
> we cannot remove null from JavaScript, but we can pretend it doesn't exist
Even if it does become general convention to not use null, as a developer, you cannot depend on that convention and skip null checks in favor of undefined, because null is deeply engrained into the language itself.
So... we can't really pretend that it doesn't exist
So if anything, you should not set something as undefined, but you can update something as null.