haumea-lang / spec

The official Haumea specification.
MIT License
0 stars 0 forks source link

Types #4

Closed BookOwl closed 7 years ago

BookOwl commented 7 years ago

Continuing discussion from https://github.com/haumea-lang/haumea/issues/4

TheMonsterFromTheDeep commented 7 years ago

So I've made some progress on implementing some C for lists, but I'm not really sure what to do next. :/

I think some sort of Haumea framework for C is needed for this to really work out - for example, right now there is no good way for the C I've written to handle what happens when somebody tries to access items out of bounds.

The other problem is that using C's type system directly won't work out too well, as there are no general methods for things like comparison - this means that I can't write something like an indexOf(item) method for lists, because it would fail on strings, which require a different method of comparison.

I think what will end up happening is that some sort of general system will evolve that provides some set of methods for some particular type, as well as info about whether that type supports certain methods, so probably something like:

/* The 'int' return type is used instead of boolean here */
int int_equals(int a, int b);
int int_supports_equals = 1;

int int_gt(int a, int b); /* 'greater than' */
int int_supports_gt = 1;

...

int string_equals(string a, string b);
int string_supports_equals = 1;

int string_supports_gt = 0;

Although, even this might not work if types become more general.

One other problem is that with the way lists currently work, like:

list_int *myInts = list_int_empty();
for(int i = 0; i < 10; ++i) {
    list_int_add(myInts, i);
}
list_int_free(myInts);

lists of certain types won't work, simply due to the restriction on length of C names.

/* Some c compilers won't be able to tell these apart: */
list_list_list_list_list_list_int *myUglyList;
list_list_list_list_list_list_list_int *myUglierList;
TheMonsterFromTheDeep commented 7 years ago

Actually, I'm now thinking that the best way to do this may be to implement lists through casting - each list merely has a void pointer for its data, and it's casted whenever it's accessed.

That way, the type name wouldn't really matter, and lists could stack infinitely.

BookOwl commented 7 years ago

What do you guys think of this syntax?

variable x is a Type /* Declare a variable's type */
to foo ... /* Declares a procedure that returns an Integer */

to bar ... returns a String /* A function that takes zero arguments and returns a String */

/* A function that takes an Integer and a String and returns a String */
to replicate with (times is an Integer, str is a String) do
  if times = 0 then return ""
  else return str + replicate(times - 1, str)
end 
returns a String
BookOwl commented 7 years ago

Or how about putting the prototype on a different line?

function replicate takes an Integer, a String, and returns a String
to replicate with (times, str) ...
BookOwl commented 7 years ago

If no prototype is found for the function, it assumes Integer for all the types involved.

BookOwl commented 7 years ago

Asking @liam4 @nanalan @jonathan50 @algmwc5 @jupiterio @joker314 @tjvr and @Firedrake969 for input

bates64 commented 7 years ago

Return syntax is a bit weird, and I don't like the seperate prototype idea. To be honest, I still like

string x
set x to "foobarbaz"
display(replicate(4, x))
/* foobarbazfoobarbazfoobarbazfoobarbaz */

to replicate with (integer times, string str) do
  if times = 0 return ""
  else return str + replicate(times - 1, str)
end

But I'm still unsure on defining the return type.

BookOwl commented 7 years ago

The return type is the only thing that I'm not quite sure how to define either.

bates64 commented 7 years ago

Maybe considering how functions are defined could be different. If possible, all functions could be lambdas?

set replicate to string with (integer times, string str) return "no"
TheMonsterFromTheDeep commented 7 years ago

Is the normal, C-style type declaration not good enough?

integer x
string hello
set x to 1
set hello to "Hello"
/* or even: */
set integer answer_to_everything to 42

Functions are, I think, the hardest to deal with. It's possible they could have type inference:

to factorial with (integer n) do
    if n = 0 return 1 /* returns an int because below statement returns an int */
    else return n * factorial (n - 1)
end

However I think this is potentially really confusing. I still think "as" is not a bad choice:

to factorial with (integer n) as integer do
/* or */
to factorial as integer with (integer n) do
jeandrek commented 7 years ago

@nanalan I don't think to makes sense without a name following it. But to could be syntactic sugar for declaring a variable and assigning a procedure created with a lambda expression to the new variable?

BookOwl commented 7 years ago

@TheMonsterFromTheDeep, "as" is definitely the best choice for return types. I'm not so sure about the C style variable declarations.

What do you guys think about the prototype idea?

bates64 commented 7 years ago

I don't like the seperate prototype idea.

I'm all for @TheMonsterFromTheDeep's ideas.

bates64 commented 7 years ago

@BookOwl looks like everyone (bar you) likes @TheMonsterFromTheDeep's ideas - time for implementation?

BookOwl commented 7 years ago

Sure. You can decide if you want to use to factorial with (integer n) as integer do or to factorial as integer with (integer n) do. I like both the same amount

bates64 commented 7 years ago

We can support both @BookOwl if we really want - it's a matter of preference.

BookOwl commented 7 years ago

Let's just use to factorial with (integer n) as integer do then.

BookOwl commented 7 years ago

Type Syntax

/* Variables */
string x
integer y
float z

/* Function types */
to foo do ... /* If there are no parameters and no return type, Haumea assumes an integer return type */
to blah as string do ... /* But you can change it */
to baz with (integer n, string s) as string do ... /* Declaring the argument and return types */
bates64 commented 7 years ago

Haumea assumes an integer return type

Surely it should assume that it returns none?

bates64 commented 7 years ago

Also global variables with global?

set global string world to "Earth"

display("Hello, " + world)
BookOwl commented 7 years ago

Haumea assumes an integer return type

Surely it should assume that it returns none?

In haumea functions that don't return anything return the integer 0.

bates64 commented 7 years ago

That feels a little unintuitive..


We should have booleans too, don't you think?

set boolean i_can_use_haumea to true
BookOwl commented 7 years ago

What do booleans have to do with default return values?

bates64 commented 7 years ago

I meant them as different things - why not have a none type which cannot be assigned to a variable? e.g.

to nine_plus_ten do
  display(21)
  /* implicitly returns none */
end

set twenty_one to nine_plus_ten() /* compiler error, variable cannot be `none` */
BookOwl commented 7 years ago

That sounds good to me.

bates64 commented 7 years ago

Adding this to the spec now.

BookOwl commented 7 years ago

For global variables, I think that any variables declared at the top level should be global, and variables declared in a function should be local.

integer x /* This is a global */
to blah do
  integer y /* This is local */
end
to baz do 
  integer x /* Shadows the global variable */
end
bates64 commented 7 years ago

Defining a global variable inside a local scope can be helpful though.

BookOwl commented 7 years ago

When?

bates64 commented 7 years ago

Sorry, I meant assigning a global variable. Nevermind :stuck_out_tongue_winking_eye:

BookOwl commented 7 years ago

This all looks good, but isn't it easier to say that if a function doesn't return anything it must only be used as a procedure, instead of making up a none type that can't be used?

bates64 commented 7 years ago

a procedure

That's basically it. Being none, nothing can be set to its result.