Add records to manual.
This commit is contained in:
parent
940671822c
commit
51a80bb5ed
148
doc/deimos.asciidoc
Normal file
148
doc/deimos.asciidoc
Normal file
@ -0,0 +1,148 @@
|
||||
= Deimos
|
||||
Jesse Brault <jesse@jessebrault.com>
|
||||
0.1.0
|
||||
:toc:
|
||||
|
||||
== Language
|
||||
|
||||
=== Records
|
||||
|
||||
[source]
|
||||
----
|
||||
pub record Foo(bar: Int, baz: String) end
|
||||
|
||||
fn main()
|
||||
let foo = Foo(1, "Hello")
|
||||
println(foo.bar()) // 1
|
||||
println(foo.baz()) // Hello
|
||||
|
||||
let foo2 = Foo(1, "Hello")
|
||||
println(foo == foo2) // true
|
||||
end
|
||||
----
|
||||
|
||||
Records are essentially classes whose data members are all shallowly immutable. The data members of the constructor are
|
||||
always inherently public; it is a syntax error to include the `pub` keyword.
|
||||
|
||||
Records inherently have methods named after the data fields to get the fields' values. It is an error to redeclare a
|
||||
data field's method. Additionally, records inherently implement `Eq` and `Hash`, but each only if the constituent
|
||||
members also implement those traits. *Records that do _not_ automatically implement `Eq` _and_ `Hash` must manually
|
||||
implement the missing traits; it is an error to not do so.*
|
||||
|
||||
==== DVM/Performance Considerations
|
||||
|
||||
Records are interned and compared based on their data content, much like Strings (however, while Strings are primitive,
|
||||
records are not). References to the record's shared data are cloned in the VM for all same-valued instances. To
|
||||
illustrate:
|
||||
|
||||
[source]
|
||||
----
|
||||
class Cat(pub sound: String) end
|
||||
|
||||
record Dog(sound: String) end
|
||||
|
||||
fn main()
|
||||
let cats: List<Cat> = []
|
||||
for i in 0..100_000 do
|
||||
cats << Cat("meow") // creates a new Cat object in memory each iteration
|
||||
end
|
||||
let dogs: List<Dog> = []
|
||||
for i in 0..100_000 do
|
||||
dogs << Dog("meow") // creates one Dog object in memory on first iteration,
|
||||
// with 100_000 references stored in dogs list
|
||||
end
|
||||
end
|
||||
----
|
||||
|
||||
==== Engineering Considerations
|
||||
|
||||
Records should be preferred against classes in most cases where the data of the class is all immutable, as this saves
|
||||
memory and should result in faster execution times for data-heavy workloads.
|
||||
|
||||
==== Extern Records
|
||||
|
||||
Extern records signify native (Rust or otherwise) objects. They are declared with the `extern` keyword. However, unlike
|
||||
plain Deimos records, all data-access methods, as well as the `Eq` and `Hash` traits' methods, must be implemented
|
||||
natively, as the Deimos compiler has no method of knowing how to actually access the inner data.
|
||||
|
||||
[source]
|
||||
----
|
||||
extern record GameCharacter(name: String) end
|
||||
----
|
||||
|
||||
== Compile Error Explanations
|
||||
|
||||
=== Not more than one constructor
|
||||
|
||||
Classes may have up to only one constructor. The following does not compile:
|
||||
|
||||
[source]
|
||||
----
|
||||
class Foo
|
||||
ctor(bar: Int) end
|
||||
ctor(baz: String) end // Error
|
||||
end
|
||||
----
|
||||
|
||||
=== Field must be initialized
|
||||
|
||||
All class fields must be initialized in their declaration, or in the constructor. It
|
||||
is an error to leave a field uninitialized.
|
||||
|
||||
[source]
|
||||
----
|
||||
class Foo
|
||||
bar: Int // Error: no initializer
|
||||
end
|
||||
|
||||
class Bar
|
||||
baz: Int // Error: no initializer
|
||||
|
||||
ctor()
|
||||
// some other stuff
|
||||
end
|
||||
end
|
||||
----
|
||||
|
||||
=== Use of field before initialization
|
||||
|
||||
A field _without_ a declared initializer (i.e., one present at its declaration, not the constructor) may not be read in
|
||||
the initializer of any other field or constructor variable, as the language does not guarantee a specific ordering of
|
||||
field initialization and cannot statically analyze field/variable dependencies.
|
||||
|
||||
[source]
|
||||
----
|
||||
class Foo
|
||||
bar: Int
|
||||
baz = bar // Error
|
||||
end
|
||||
|
||||
class Bar
|
||||
foo: Int
|
||||
baz = fnWithArg(foo) // Error
|
||||
end
|
||||
|
||||
class Baz
|
||||
foo: Int
|
||||
qux: String
|
||||
|
||||
ctor(baz: String)
|
||||
qux = foo + baz // Error: attempt to read uninitialized foo
|
||||
end
|
||||
end
|
||||
----
|
||||
|
||||
The exception to this is reading the field inside another field's initializer *only* when that expression is itself a
|
||||
closure.
|
||||
|
||||
[source]
|
||||
----
|
||||
class Foo
|
||||
bar: Int
|
||||
baz = { bar } // OK
|
||||
|
||||
ctor(bar: Int)
|
||||
self.bar = bar
|
||||
end
|
||||
end
|
||||
----
|
||||
@ -1,81 +0,0 @@
|
||||
= Deimos
|
||||
Jesse Brault <jesse@jessebrault.com>
|
||||
0.1.0
|
||||
:toc:
|
||||
|
||||
== Compile Error Explanations
|
||||
|
||||
=== Not more than one constructor
|
||||
|
||||
Classes may have up to only one constructor. The following does not compile:
|
||||
|
||||
[source]
|
||||
----
|
||||
class Foo
|
||||
ctor(bar: Int) end
|
||||
ctor(baz: String) end // Error
|
||||
end
|
||||
----
|
||||
|
||||
=== Field must be initialized
|
||||
|
||||
All class fields must be initialized in their declaration, or in the constructor. It
|
||||
is an error to leave a field uninitialized.
|
||||
|
||||
[source]
|
||||
----
|
||||
class Foo
|
||||
bar: Int // Error: no initializer
|
||||
end
|
||||
|
||||
class Bar
|
||||
baz: Int // Error: no initializer
|
||||
|
||||
ctor()
|
||||
// some other stuff
|
||||
end
|
||||
end
|
||||
----
|
||||
|
||||
=== Use of field before initialization
|
||||
|
||||
A field _without_ a declared initializer (i.e., one present at its declaration, not the constructor) may not be read in
|
||||
the initializer of any other field or constructor variable, as the language does not guarantee a specific ordering of
|
||||
field initialization and cannot statically analyze field/variable dependencies.
|
||||
|
||||
[source]
|
||||
----
|
||||
class Foo
|
||||
bar: Int
|
||||
baz = bar // Error
|
||||
end
|
||||
|
||||
class Bar
|
||||
foo: Int
|
||||
baz = fnWithArg(foo) // Error
|
||||
end
|
||||
|
||||
class Baz
|
||||
foo: Int
|
||||
qux: String
|
||||
|
||||
ctor(baz: String)
|
||||
qux = foo + baz // Error: attempt to read uninitialized foo
|
||||
end
|
||||
end
|
||||
----
|
||||
|
||||
The exception to this is reading the field inside another field's initializer *only* when that expression is itself a
|
||||
closure.
|
||||
|
||||
[source]
|
||||
----
|
||||
class Foo
|
||||
bar: Int
|
||||
baz = { bar } // OK
|
||||
|
||||
ctor(bar: Int)
|
||||
self.bar = bar
|
||||
end
|
||||
end
|
||||
----
|
||||
Loading…
Reference in New Issue
Block a user