ooc-lang / rock

:ocean: self-hosted ooc compiler that generates c99
http://ooc-lang.org/
MIT License
404 stars 40 forks source link

Add template functions to the language #938

Closed alexnask closed 8 years ago

alexnask commented 9 years ago

This could be done by "turning" inline generic functions into templated functions (this may or may not have been the case in the past, I vaguely remember something about it).

For example:

adder: inline func <T> (a, b: T) -> T {
    a + b
}

"#{adder(2, 40)}" println()

adder("hi", 12) // Resolve error: No operator + for String, Int

f: func <T> (arg: T) {
    f(arg, arg) // This should also error out, can't actually pass "real" generics
}

This would be a real challenge to implement but I do think it is a worthwhile investment.
Alternatively, to make it clearer that the function is templated instead of using generics, this syntax (which matches cover templates) would be better (?):


adder: template<T> func (a, b: T) -> T {
    a + b
}

// Perhaps even allow

adder: template<T, U> func(a, b: T) -> U {
    a + b
}
alexnask commented 9 years ago

This can already be emulated using a stateless template cover with static functions, although I'm not sure if you can (correctly) get the address of those functions.

I just think it's nicer that way.

Ideally, it should also be possible to generate and take the address of such a function in a context sensitive way.

For example:

apply: func(a, b: Int, f: Func (Int, Int) -> Int) -> Int {
    f(a, b)
}

mult: template<T> func(a, b: T) -> T {
    a * b
}

// Ideally, should generate mult<Int> and take it's address
apply(0, 0, mult)

Otherwise, I guess we would need to be able to manually instantiate the templates and thus add some kind of syntax:

apply(0, 0, mult<Int>)

Imho, this would be too confusing because of the generic/template "clash".

Edit:
It is indeed possible to correctly take the address of a static cover template func, as seen below:

Adder: cover template <T> {
    apply: static func (a, b: T) -> T {
        a + b
    }
}

doSomething: func (a, b: Int, f: Func (Int, Int) -> Int) -> Int {
    f(a, b)
}

doSomething(0, 42, Adder<Int> apply) toString() println()
alexnask commented 9 years ago

We could even take the Java/C++ lambda route and generate cover templates as seen in the previous comment then replace accesses to the function to the static cover method.

This would still require some way to instantiate the function's templates manually, though, and I personally think it is an inelegant solution.

Edit:

Also, this adds some overhead, as it generates a Class object for each different argument combination, which makes sense for a template cover in the ooc typesystem, but is not necessary for a single function.

alexnask commented 8 years ago

This is not needed, closing.

vendethiel commented 8 years ago

why not needed? :)

alexnask commented 8 years ago

@vendethiel I think adding class templates and working a bit on inferring will be enough templates for us.
You can basically do this with the trick I showed above anyways.

After I add class templates, rock will be considered feature-complete, at least in language features.
Of course, additions to the sdk and rock's functionality itself will be always welcome.

vendethiel commented 8 years ago

Okay, thanks!