Null object: Difference between revisions

11,223 bytes added ,  2 months ago
No edit summary
(15 intermediate revisions by 8 users not shown)
Line 715:
(f '( a b c)) → a b c
</syntaxhighlight>
 
=={{header|Ecstasy}}==
In Ecstasy, everything is an object, including the <span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span> value. <span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span> is the only value in the [https://github.com/xtclang/xvm/blob/dd32c2eba0930c4a59f4ba7507c6af37818d255c/lib_ecstasy/src/main/x/ecstasy.x#L21 <span style="background-color: #e5e4e2"><tt>&nbsp;Nullable&nbsp;</tt></span> enumeration defined in the "<tt>ecstasy</tt>" core module]. As a regular old object, the <span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span> value has a regular old class, a regular old type, and it implements regular old methods such as <span style="background-color: #e5e4e2"><tt>&nbsp;toString()&nbsp;</tt></span>. There are, however, a few specific ways in the language (both the compiler and runtime) that <span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span> is treated specially:
 
<ul><li>Syntax support: A type union with <span style="background-color: #e5e4e2"><tt>&nbsp;Nullable&nbsp;</tt></span> can be indicated with the postfix "?"; for example, the long-hand type union syntax <span style="background-color: #e5e4e2"><tt>&nbsp;Nullable|String s&nbsp;</tt></span> can be replaced using the short-hand notation <span style="background-color: #e5e4e2"><tt>&nbsp;String? s&nbsp;</tt></span>.
</li><li>Syntax support: The postfix "?" operator is a short-circuiting null value test, allowing a cascading sequence of null tests to replace a series of nested if statements; for example, <span style="background-color: #e5e4e2"><tt>&nbsp;Int x = a?.b()?.c?[i?].d? : e;&nbsp;</tt></span> will result in the value of <span style="background-color: #e5e4e2"><tt>&nbsp;e&nbsp;</tt></span> if any of the expressions <span style="background-color: #e5e4e2"><tt>&nbsp;a&nbsp;</tt></span>, <span style="background-color: #e5e4e2"><tt>&nbsp;a.b()&nbsp;</tt></span>, <span style="background-color: #e5e4e2"><tt>&nbsp;a.b().c&nbsp;</tt></span>, <span style="background-color: #e5e4e2"><tt>&nbsp;i&nbsp;</tt></span>, or <span style="background-color: #e5e4e2"><tt>&nbsp;a.b().c[i].d&nbsp;</tt></span> are <span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span>.
</li><li>Syntax support: The expression <span style="background-color: #e5e4e2"><tt>&nbsp;x ?: y&nbsp;</tt></span> will use the value <span style="background-color: #e5e4e2"><tt>&nbsp;y&nbsp;</tt></span> iff <span style="background-color: #e5e4e2"><tt>&nbsp;x&nbsp;</tt></span> is <span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span>, and the corresponding assignment statement <span style="background-color: #e5e4e2"><tt>&nbsp;x ?:= y&nbsp;</tt></span> will assign <span style="background-color: #e5e4e2"><tt>&nbsp;y&nbsp;</tt></span> to <span style="background-color: #e5e4e2"><tt>&nbsp;x&nbsp;</tt></span> iff <span style="background-color: #e5e4e2"><tt>&nbsp;x&nbsp;</tt></span> is <span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span>.
</li><li>Syntax support: The assignment statement <span style="background-color: #e5e4e2"><tt>&nbsp;x ?= y&nbsp;</tt></span> will assign <span style="background-color: #e5e4e2"><tt>&nbsp;y&nbsp;</tt></span> to <span style="background-color: #e5e4e2"><tt>&nbsp;x&nbsp;</tt></span> iff <span style="background-color: #e5e4e2"><tt>&nbsp;y&nbsp;</tt></span> is <b>not</b> <span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span>.
</li><li>The assignment operator <span style="background-color: #e5e4e2"><tt>&nbsp;?=&nbsp;</tt></span> also yields a <span style="background-color: #e5e4e2"><tt>&nbsp;Boolean&nbsp;</tt></span> value indicating the <b>non-</b>null-ness the right hand side value, which can be used in an <span style="background-color: #e5e4e2"><tt>&nbsp;if&nbsp;</tt></span> condition, <span style="background-color: #e5e4e2"><tt>&nbsp;while&nbsp;</tt></span> condition, etc.; for example, <span style="background-color: #e5e4e2"><tt>&nbsp;if (x ?= y) ...&nbsp;</tt></span> will take the "then" branch if <span style="background-color: #e5e4e2"><tt>&nbsp;y&nbsp;</tt></span> is non-null and therefore <span style="background-color: #e5e4e2"><tt>&nbsp;x&nbsp;</tt></span> is definitely assigned, otherwise it will take the "else" branch and <span style="background-color: #e5e4e2"><tt>&nbsp;x&nbsp;</tt></span> will not be definitely assigned.
</li><li><span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span> values are treated specially by equality comparisons: Normally, the compiler prevents two references of different compile-time types from being compared (such as <span style="background-color: #e5e4e2"><tt>&nbsp;Int&nbsp;</tt></span> and <span style="background-color: #e5e4e2"><tt>&nbsp;String&nbsp;</tt></span>), but an explicit exception is made that allows a nullable type to be compared with a non-nullable type (such as <span style="background-color: #e5e4e2"><tt>&nbsp;String?&nbsp;</tt></span> and <span style="background-color: #e5e4e2"><tt>&nbsp;String&nbsp;</tt></span>).
</li></ul>
Other than these specific compiler and runtime features, <span style="background-color: #e5e4e2"><tt>&nbsp;Null&nbsp;</tt></span> is treated exactly like every other object.
 
 
<syntaxhighlight lang="java">
module NullObject {
void run() {
@Inject Console console;
console.print($"Null value={Null}, Null.toString()={Null.toString()}");
 
// String s = Null; // <-- compiler error: cannot assign Null to a String type
String? s = Null; // "String?" is shorthand for the union "Nullable|String"
String s2 = "test";
console.print($"{s=}, {s2=}, {s==s2=}");
 
// Int len = s.size; // <-- compiler error: String? does not have a "size" property
Int len = s?.size : 0;
console.print($"{len=}");
 
if (String test ?= s) {
// "s" is still Null in this test, we never get here
} else {
s = "a non-null value";
}
 
// if (String test ?= s){} // <-- compiler error: The expression type is not nullable
s2 = s; // at this point, s is known to be a non-null String
console.print($"{s=}, {s2=}, {s==s2=}");
}
}
</syntaxhighlight>
 
{{out}}
<pre>
Null value=Null, Null.toString()=Null
s=Null, s2=test, s==s2=False
len=0
s=a non-null value, s2=a non-null value, s==s2=True
</pre>
 
=={{header|Eiffel}}==
Line 754 ⟶ 803:
<syntaxhighlight lang="elixir">iex(3)> if nil, do: "not execute"
nil</syntaxhighlight>
 
=={{header|EMal}}==
<syntaxhighlight lang="emal">
^|
| EMal has the Variable type (and its keyword var) that is the nullable universal supertype.
| EMal has the Void type (and its keyword void) that holds only one value: null.
| EMal has not nullable types (logic, int, real, text, blob), but null equality is always allowed.
|^
var a # defaults to null
int b # defaults to 0
void c # only one allowed value: null
writeLine("nullable var equals to not nullable int: " + (a == b)) # allowed, false
^| if the data type of a is void we are sure that a is null |^
writeLine("type of a equals to Void data type: " + (generic!a == void)) # true
writeLine("integer value " + b + " equals to null: " + (b == null)) # allowed, always false
writeLine("a void value equals to null: " + (c == null)) # always true</syntaxhighlight>
{{out}}
<pre>
nullable var equals to not nullable int: ⊥
type of a equals to Void data type: ⊤
integer value 0 equals to null: ⊥
a void value equals to null: ⊤
</pre>
 
=={{header|Erlang}}==
Line 862 ⟶ 934:
</pre>
 
=={{header|GDScript}}==
Godot has a null value. Here is an example of dealing with null.
<syntaxhighlight lang="gdscript">
extends Node2D
 
func _ready() -> void:
var empty : Object
var not_empty = Object.new()
# Compare with null.
if empty == null:
print("empty is null")
else:
print("empty is not null")
# C-like comparation.
if not_empty:
print("not_empty is not null")
else:
print("not_empty is null")
return
</syntaxhighlight>
{{out}}
<pre>
empty is null
not_empty is not null
</pre>
 
=={{header|Go}}==
Line 1,091 ⟶ 1,189:
 
=={{header|langur}}==
Null can be compared for directly, using equality operators, or can be checked with the isNull() function. Operators ending with a ? mark propagate null. A null in an expression test is a non-truthy result.
 
{{works with|langur|0.10}}
Prior to 0.10, multi-variable declaration/assignment would use parentheses around variable names and values.
 
<syntaxhighlight lang="langur">val .x, .y = true, null
Line 1,393 ⟶ 1,488:
=={{header|MAXScript}}==
<syntaxhighlight lang="maxscript">if obj == undefined then print "Obj is undefined"</syntaxhighlight>
 
=={{header|min}}==
<syntaxhighlight lang="min">null null? puts!</syntaxhighlight>
{{out}}
<pre>true</pre>
 
=={{header|Modula-3}}==
Line 2,101 ⟶ 2,201:
if {![dict exists $dic nullval]} ...</syntaxhighlight>
Note that lists do not support anything like nulls, since they are strictly sequences of values.
 
=={{header|TXR}}==
=={{trans|Common Lisp}}==
TXR Lisp has a <code>nil</code> symbol which serves as the empty list and Boolean false, like Common Lisp and similar dialects. It is a very important symbol which plays a central role.
 
Variable definitions, global and local, without initial value expressions take on the value <code>nil</code>. Elements of newly created vectors and structure slots are <code>nil</code> by default. Optional function parameters that don't receive arguments are given <code>nil</code> arguments by default. Many functions which search for something use <code>nil</code> for indicating not found.
 
Object-oriented programming in TXR Lisp is done with structures, which do not provide a CLOS-like object system. The <code>nil</code> object isn't a structure, and so it cannot take slot references, or method invocation. Only structures have methods, which means that it's not possible to define a null object method <code>m</code> such that <code>obj.(m)</code> can be invoked if <code>obj</code> is an expression evaluating to <code>nil</code>.
 
The Gang-of-Five Null Object Pattern can be employed: defining struct types that behave like null. This null object doesn't have to be related by inheritance to the structs in conjunction with which it is used.
 
<syntaxhighlight lang="txrlisp">
(defstruct null-widget ()
(:method popularity (me) 0))
 
(defvarl null-widget (new null-widget))
 
(defstruct real-widget ()
pop
(:method popularity (me) me.pop))</syntaxhighlight>
 
In situations when a null object would be used simply to provide safe treatment of null without the verbosity of checks for its presence, and a default value of <code>nil</code> is acceptable, TXR Lisp has null-safe slot and method access: <code>obj.?slot</code>, <code>obj.?(method arg)</code>.
 
The expression <code>w.?(popularity)</code> will evaluate to <code>nil</code> if <code>w</code> is <code>nil</code>, being equivalent to <code>(if w w.(popularity))</code>, except that <code>w</code> is evaluated only once.
 
Like in Common Lisp, <code>nil</code> an instance of the type <code>null</code>, which is a unit type having only that instance. And <code>nil</code> is also the name of the bottom type of the type system: the <code>nil</code> type is the subtype of every type, including itself.
 
Like in Common Lisp, the expression <code>(or a b c ...)</code> evaluates the arguments from left to right, returning the value of the leftmost one which does not evaluate to <code>nil</code>.
 
<syntaxhighlight lang="txrlisp">;; Find widget in one of three places in order
(defun find-widget (name)
(or [%widget-hash% name]
(lookup-local-widget name)
(lookup-global-widget name)))</syntaxhighlight>
 
=={{header|Ursa}}==
Line 2,168 ⟶ 2,302:
 
End Sub
</syntaxhighlight>
 
=={{header|V (Vlang)}}==
V (Vlang) does not have nor normally allow null or nil (also called "the billion dollar mistake"):
 
1) All primitive types/variables have default values.
 
2) For arrays and structs, default values are automatically assigned.
 
3) Usage of voidptr or nil, only done in unsafe, and is usually only for the purposes of interoperability with other languages.
<syntaxhighlight lang="v (vlang)">
// Null or nil not used, default values for various primitive types/variables instead:
 
a_string :=''
a_bool := false
an_int := 0
[3]string{} // ['', '', '']
[3]bool{} // [false, false, false]
[3]int{} // [0, 0, 0]
</syntaxhighlight>
 
Line 2,185 ⟶ 2,338:
 
It is always easy to test for nullness either by querying a variable's type or checking the value of a boolean expression involving a potentially null variable.
<syntaxhighlight lang="ecmascriptwren">// Declare a variable without giving it an explicit value.
var s
 
885

edits