jbcoe / mylang

A lexer, parser, interpreter, JIT and AOT compiler and runtime written in Rust for a new (simple) language
MIT License
3 stars 1 forks source link

Design proposal: add a dynamic type #84

Open jbcoe opened 3 years ago

jbcoe commented 3 years ago

Should we add support for dictionary/table like types to mylang making it very dynamic

https://www.lua.org/pil/2.5.html https://www.lua.org/pil/11.1.html

If not we probably want static typing and need a plan for extra types we'll need.

Maybe we could do both and have a dynamic_table (dyn_table) type that bypasses the type checker as its entries can change at runtime. This could be interesting as it's the opposite design decision taken by Python (+mypy type checking) where everything is untyped (Any) by default.

https://mypy.readthedocs.io/en/stable/kinds_of_types.html#the-any-type

Possible syntax for dynamic tables:

let mut a = dynamic; #new keyword, do we want `dyn` instead? Do we need `mut`?
let a.0 = 5;
let mut a.1 = "Hi";
let a.key = fn (a, b) { return a; };
let a["key with space"] = 3.14159;

a.1 = "Bye";
philipcraig commented 3 years ago

We should take a look at https://github.com/gluon-lang/gluon and decide how mylang is different. Also, notwithstanding my earlier suggestions that interop with C is the best one can hope for, gluon says it offers native Rust interop

philipcraig commented 3 years ago

I prefer dyn to dynamic as a keyword, as I seem to see dyn used more often as a language keyword

jbcoe commented 3 years ago

A bit more time and a bit more (un-researched) thought:

I propose the following rules for mylang:

1) inputs to functions are always immutable. 2) functions must return something. 3) evaluation can be replayed (run in reverse) so can't take input from anything but mylang source. 4) subroutines can have side effects (print, log, call function etc) but they cannot effect later behaviour of the program (see 3). 5) Types are deduced and static.

Very loosely inspired by the above I propose the following snippets of syntax for the dyn type. (I think we want a dynamic type to exist as it makes JIT and typing hard.)

let a = dyn { x: 3.14159, y: func(x) { return x; }, z: "Some string" };
let b = a.y(a.x); # b is 3.14159
ley a.w = 7; # Fails, a is not `mut`
let mut a = dyn {};
let a.x = 3.14159;
a.x = -2.6; # succeeds (once we've implemented assignment), a is `mut`
let f = func(x) { return x.a; }; 
let z = f({a: 10}); # z is 10

I think we can get a dynamic type checker to ensure that dyn values will have the right keys.

What do people think?

ajbennieston commented 3 years ago

So dyn is syntactic sugar for dictionary lookup? That is, the actual static type of an object will be SomeImplDictType and if we encounter operator. whose LHS is such an object we translate it to a dictionary lookup instead of an offset per a C-style struct?

Keys in the dict would be valid mylang identifiers (although you use 0 and 1 in the first motivating example in this thread, so perhaps they're arbitrary alphanumeric sequences?) and values of those keys would have a (static?) type determined by their first use (i.e. fixed from that point onward)?

jbcoe commented 3 years ago

That’s the plan. We can define protocols later on that check that various dictionary lookups give the right return types.

Design is inspired by Lua tables and CPython internal a.