ballercat / walt

:zap: Walt is a JavaScript-like syntax for WebAssembly text format :zap:

Home Page:https://ballercat.github.io/walt/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Nested structs and functions within structs

ballercat opened this issue · comments

Goal

Allow for nested structs and functions within structs.

Overview

Depends on (#28)

Closures are cool, but to be useful you'd want to return an object/struct with a closure or another struct as a field.

Basically, this syntax should be possible

type lambda Closure = () => i32;
type Struct = {
   increment: Closure,
   decrement: Closure
};
function getActions(): Struct {
  let x: i32 = 0;
  const result: Struct = 0;
  result = {
     increment: (): i32 => { 
        x += 1;
        return x;
     },
    decrement: (): i32 => {
        x -= 1;
        return x;
    },
    getX: (): i32 => { return x; }
  };
  return result;
}

export function test() : i32 {
  const actions: Struct = getActions();
  actions.increment();
  actions.increment();
  actions.decrement();
  // should be 1
  return actions.getX();
}

This should make the syntax much more expressive and allow for a wide range of applications.

Acceptance Criteria

  • Allow nested struct types within other structs
  • Allow closure types within structs
  • Test everything

Why using the lambda keyword?
In TS & Flow the syntax is:

type Closure = () => i32;

@iddan

It's easier to compile this way.

I assumed, but I think that introducing a new keyword is problematic. Maybe this can be solved with a special generic?

How would a generic function type work for this? Could you be more specific, what syntax would be an alternative?

For background, I initially did use regular functions types for closures, but the two have fundamentally different representations in the binary. This means that syntax becomes ambiguous, where a function, for example, can return either a closure or a function pointer. By extension, any use of a return value from a function like this is now also ambiguous.

All this means is that types have to be specific to the thing they represent. If there is a way to express a closure being different with existing syntax, I'm all for it though.

It also may be possible to omit the lambda keyword in the future, but I won't fix this until we are well on our way to a 1.0.0 release. Unless someone puts up an MR to resolve the ambiguity I described above.

You can mark external functions explicitly:

-type Log = (i32) => void;
+type Log = External<(i32) => void>;

Cool, so are you suggesting that we should have a built-in type for Lambda instead of a keyword? That could work I think with something like this

-type lambda Closure = () => i32;
+type Closure = Lambda<() => i32>;

or

-type lambda Closure = () => i32;
+type FunctionType = () => i32;
+type Closure = Lambda<FunctionType>

I personally have not seen this particular use of generics before, but this could work. Would need a type parser change/PR but I like it 👍

Might I also suggest replacing the 'type' keyword for 'lambda'. For example 'lambda Func = () => i32’

Note: I'm on my phone and I'm unsure how the syntax style formatting works.