diff --git a/doc/deimos.asciidoc b/doc/deimos.asciidoc new file mode 100644 index 0000000..a0f2955 --- /dev/null +++ b/doc/deimos.asciidoc @@ -0,0 +1,148 @@ += Deimos +Jesse Brault +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 = [] + for i in 0..100_000 do + cats << Cat("meow") // creates a new Cat object in memory each iteration + end + let dogs: List = [] + 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 +---- \ No newline at end of file diff --git a/doc/deimos.asciidoc.adoc b/doc/deimos.asciidoc.adoc deleted file mode 100644 index fa9ffc1..0000000 --- a/doc/deimos.asciidoc.adoc +++ /dev/null @@ -1,81 +0,0 @@ -= Deimos -Jesse Brault -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 ----- \ No newline at end of file