Last active
August 29, 2015 14:06
-
-
Save dcbishop/dede2638d097482ab073 to your computer and use it in GitHub Desktop.
Language Ideas
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// What if a function and struct are the same 'thing', I'll just call it a 'block'. | |
MyStruct { | |
x : int = @ // @ here means not optional, *must* provide this when constructed. | |
y : int = 0 // Default but optional initilization | |
} | |
// And a function has the same syntax, just with code | |
// There is no function argument signature, it uses the decelerations in the order they appear. | |
my_func { | |
a : int = @ | |
b : int = 2 // Default for optional argument | |
return a*b // Type deduction, if needed could force a type with a cast. | |
} | |
m := MyStruct(2) | |
n := MyStruct(4, 3) | |
x := MyStruct() // ERROR: missing arg | |
x := MyStruct(@) // Maybe allow an override, here memory is uninitialized. | |
// Is equivalent to | |
// struct my_struct_t { | |
// int x; | |
// int y; | |
// }; | |
// my_struct_t MyStruct(int x, int y=0) { return my_struct_t{x, y} } | |
// And similarly the function... | |
g := my_func(1) | |
f := my_func(1,2) | |
// What if member functions where just regular functions that allowed both an | |
// OOP and non-OOP syntax | |
// Example: Implementing a class | |
MyClass { | |
name : string = @ | |
} | |
getName { | |
self : MyClass = @ | |
return self.name | |
} | |
my_obj := MyClass("Steve") | |
// These 2 calls are equivalent: | |
getName(my_obj) | |
my_obj.getName() | |
// Maybe whitespace, its generally eaiser to edit since you don't have to close brackets | |
// everywhere and looks cleaner. But I'll stick to braces for the examples. | |
// The use of : like Python could also be confusing with the decelerations. | |
my_func: | |
x : int = @ | |
return x*x | |
// The 1st struct is effectively an implicit factory function, so in some ways everything is a function: | |
my_struct { | |
// allocate_memory must either be on the stack or heap depending on the caller | |
// The ! here is like := but the arg isn't overridden by the caller | |
// (just theoretical since this entire section would be done by the compiler, but it could be used elsewhere?) | |
self != &allocate_memory(sizeof(my_struct)).cast(my_struct) | |
self.x := default_of(my_struct.x) // These would be overwritten by the caller if they provide args | |
self.y := default_of(my_struct.y) | |
return self | |
} | |
// There probably needs to be some simple way to tell the difference | |
// between a function argument that should be given when it's called | |
// and an internal value to accidental prevent misuse and provide | |
// documentation. Maybe a keyword or sub block. | |
my_func { | |
a : int = @ // This *must* be given when called. | |
b : int = 1 // Default arguments! But still overridable by the caller. | |
a = another_func(a)+12 | |
c := another_func(b+1) // Theoretically this could be overridden by the caller providing a 3rd arg | |
d = my_struct(a, c) | |
return d | |
} | |
// In this example everything before the --- is a function argument and | |
// anything after isn't. | |
my_func { | |
a : int = @ | |
b : int = 6 | |
--- | |
ans : int = a+b+3 | |
return ans | |
} | |
// Eg... | |
my_func(2) // a is 2, b is 6 | |
my_func(2, 9) // a is 2, b is 9 | |
my_func(2, 9, 10) // Should error as 'ans' is internal | |
// Could be an alternative to --- to separate a arguments in a function form the internal values. | |
some_thing { | |
x : int = @ // No default so this is required | |
y : int = @ 99 // This is optional | |
z : int = 99 // This isn't considered part of the function signature. Just a normal value initialization. | |
a := 99 // Type deduction | |
} | |
// Or using a subblock to specify arguments | |
some_thing { | |
args { | |
x : int = 100 | |
y : int = 100 | |
} | |
internal: int = 100 | |
} | |
// With whitespace it starts to look a little like YAML | |
some_thing: | |
args: | |
x: int = 100 | |
y: int = 100 | |
internal: int = 100 | |
// nested subblocks allow for modules/namespaces | |
math { | |
point { | |
x : int = 0 | |
y : int = 0 | |
} | |
add { | |
a : int = @ | |
b : int = @ | |
return a + b | |
} | |
add { // Function type overloading? | |
a : point = @ | |
b : point = @ | |
c := point( | |
add(a.x, b.x), | |
add(a.y, b.y), | |
) | |
return c | |
} | |
} | |
// Allow nested... | |
big_func { | |
little_func { | |
a : int = @ | |
return a * 1000 | |
} | |
b := little_func(1) | |
c := little_func(2) | |
return b+c | |
} | |
// Default getters and setters? Or allow overriding values with a function if desired? | |
some_thing { | |
x : int | |
} | |
// Standard usage | |
my_thing := some_thing(3) | |
my_thing.x = 4 // is equivalent to my_string.x(4) | |
y := my_thing.x // is equivalent to y := my_string.x() | |
// Later if the programmer decides to use a setter/getter | |
some_thing { | |
x_ : int | |
} | |
x { | |
self : some_thing = @ | |
self.x := self.x // By default self.x will be assigned itself (which should hopefully be optimized out), unless its overridden as the 2nd argument to the call | |
--- | |
return self.x // With optimization, I assume we can ignore this if it isn't used? | |
} | |
// Function tricks? | |
p := math.point(3, 4) // Normal assignment, no pointer | |
p_ptr := &math.point(3, 4) // This would be the address of the returned value, so maybe use | make a functor? | |
add_stuff := |math.add(@, @) // Maybe using @ here overrides the initialization requirement | |
// leaving dangerous uninitialized memory (maybe add 'unsafe' keyword/attribute). | |
// Otherwise just pass in a default. | |
// Also consider the following possibilities | |
add_stuff := math.add // What happens here? An alias? | |
// Pointer to a function | |
add_stuff := &math.add | |
// Functors, the memory would probably be allocated in add_stuff so it would't need a stack. | |
// or any other memory allocation. (although compilers do tricks like that already). | |
// But in this case at the cost (or feature) of possible side effects of previous functions run... | |
add_stuff := |math.add(@, @) | |
one_plus_two := add_stuff(1, 2) | |
three_plus_four := add_stuff(3, 4) | |
add_stuff.b = 10 // Settings args this way should work too, as we didn't set | |
// add_stuff.a so the previous usage of this functor is kept. | |
three_plus_ten := add_stuff() | |
// Keywords for inline? How much should optimization be left to the programmer? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment