Skip to content

Instantly share code, notes, and snippets.

@dcbishop
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dcbishop/dede2638d097482ab073 to your computer and use it in GitHub Desktop.
Save dcbishop/dede2638d097482ab073 to your computer and use it in GitHub Desktop.
Language Ideas
// 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