-
Notifications
You must be signed in to change notification settings - Fork 3
NEP4 Objects
This proposal introduces a dynamically typed concept into Neon, called Object
.
The original motivation for this is that handling JSON data is very awkward using the variant
module.
The goal is to be able to handle JSON data naturally and easily, while fitting into a strongly typed framework.
Further goals may involve interoperability with other runtime systems such as JVM objects, COM (Windows), or JS, depending on what the execution environment can offer.
This proposal would replace the variant
module.
A value of type Object
can hold a value of any type and can be reassigned with a different type.
VAR a: Object
a := 5
print(str(a))
a := "hello"
print(a)
When a type is requested that cannot be satisfied by the object, a runtime exception is raised:
VAR a: Object
a := "hello"
LET b: Number := a + 1
In this case an exception would be raised on the last statement because a
does not contain a Number
.
The =
operator compares two values.
What does the expression a = b
mean, if a
and b
are both objects?
It would be unreasonable to attempt to guess, at runtime, which type should be used for equality comparison.
It would also be unreasonable to use object identity in this case, since two different objects may represent the same value.
Probably best to disallow this specific kind of comparison.
A comparison with a value of a specific type, such as
a = 5
would do a numeric comparison after attempting to convert a
to a Number
.
Aggregate types (arrays and dictionaries) can also be stored in values of type Object
.
VAR a: Object := [1, 2, 3]
LET b: Array<Object> := a
LET c: Array<Number> := a
Note that the array can remain an array of objects (b
), or be deconstructed into an array of a specific type (c
).
In the b
case, the array could contain values of different types.
In the c
case, each element must be a Number
.
A new operator ISA
can be used to test the type of an Object
.
VAR a: Object := 5
ASSERT a ISA Number
a := [1, 2, 3]
ASSERT a ISA Array<Object>
ASSERT a ISA Array<Number>
A TRUE
result for an ISA
test means that converting the object to a value of that type will succeed.
This can be extended in the future to handle objects defined by an external system, eg. JVM. For example:
EXTENSION OBJECT JavaObject
LET a: Object := NEW JavaObject("java.util.zip.ZipFile", "filename.zip")
LET files: Array<Object> := a.entries()
FOREACH e IN files DO
print(e.getName())
END FOREACH
The implementation of an extension OBJECT would optionally provide functions similar to the following for conversion between Neon native types.
The compiler is responsible for generating function calls behind the scenes for accesses to objects. For example, the following Neon declarations show the kinds of functions that will be used:
FUNCTION makeNull(): Object
FUNCTION makeBoolean(b: Boolean): Object
FUNCTION makeNumber(n: Number): Object
FUNCTION makeString(s: String): Object
FUNCTION makeArray(a: Array<Object>): Object
FUNCTION makeDictionary(d: Dictionary<Object>): Object
FUNCTION Object.toBoolean(self: Object): Boolean
FUNCTION Object.toNumber(self: Object): Number
FUNCTION Object.toString(self: Object): String
FUNCTION Object.toArray(self: Object): Array<Object>
FUNCTION Object.toDictionary(self: Object): Dictionary<Object>
FUNCTION Object.getArrayElement(self: Object, i: Number): Object
FUNCTION Object.getDictionaryElement(self: Object, k: String): Object
FUNCTION Object.setArrayElement(self: Object, i: Number, v: Object)
FUNCTION Object.setDictionaryElement(self: Object, k: String, v: Object)
Examples of how these might be expanded are as follows:
VAR a: Object
a := 5 | a := makeNumber(5)
LET n: Number := a | LET n: Number := a.toNumber()
a := [1, 2, 3] | a := makeArray([makeNumber(1), makeNumber(2), makeNumber(3)])
n := a[0] | n := a.getArrayElement(0).toNumber()
a[0] := 5 | a.setArrayElement(0, makeNumber(5))
LET b: Array<Number> := a | LET b: Array<Number> := []
| FOREACH x OF a INDEX i DO
| b[i] := x.toNumber()
| END FOREACH
It is not permitted to use an Object
value as an INOUT
parameter.