nim-lang / RFCs

A repository for your Nim proposals.
135 stars 26 forks source link

RFC: Variadic Generics #362

Open barcharcraz opened 10 years ago

barcharcraz commented 10 years ago

As far as I can tell Nimrod does not support any kind of variadic generic. That is a generic procedure that can take 0 or more type arguments.

The motivation for this is for functions like printf where you would like to have a variadic function where each one of the variadic parameters has a different type. The varargs feature does not do this.

Both c++ and D implement variadic generics in such a way where a parameter of type T... can be zero or more types and it can be decomposed into T1, Rest... in a parameter list.

For reference both c++ and D support this feature http://dlang.org/variadic-function-templates.html Variadic Templates, section 14.5.3 of the latest c++ draft standard (n3242) Rust has a ticket open for this at: https://github.com/mozilla/rust/issues/10124

zah commented 10 years ago

This issue have two parts:

1) Supporting the definitions of generic types such as TVariant that may depend on a list of types supplied as a parameter.

2) Supporting procs taking heterogeneously typed varargs.

For point 1, there are several existing methods that you can try to explore - you can emulate the list of types as a single tuple type param. Then you'll be able to use some easily added magics to the typetraits module or just the good old type(x) operator that will let you access the individual types of the "list". Alternatively, you can represent the list as a single static[seq[typedesc]] param. This will have the advantage that any algorithms defined over sequences will work out of the box on type lists (no need for Boost.MPL). Both methods are not covered yet in the test suite, so be prepared for bugs and please send reports.

For point 2, the currently supported way is to rely on a macro that will accept the params and directly handle them or repackage them as a tuple that will be passed to a generic proc. In the manual, you'll find an example for a safePrintf marco that makes use of this approach: http://build.nim-lang.org/docs/manual.html#special-types-typedesc

A small task on my to-do list is to automate this repackaging as a tuple in order to let you write more easily such generic procs with heterogeneous varargs.

dom96 commented 8 years ago

$50 bounty has been posted on this issue https://www.bountysource.com/issues/1446763-rfc-variadic-generics. Thanks @Henry

reactormonk commented 8 years ago

Maybe some kind of HLists? https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#heterogenous-lists

Henry commented 8 years ago

@dom96 : No problem, I like the idea of BountySource and wanted to get the ball rolling.

I am migrating from Xl2 to Nim and in Xl2 variadic generics are a fundamental part of the design being used for multi-argument, multi-type write functions and I rather like this appoach. There is an example on https://en.wikipedia.org/wiki/XL_(programming_language) and examples provided:

// Test that simple recursive definitions of variadics work
use XL.UI.CONSOLE

generic type ordered

function MyMax (X : ordered) return ordered is
    WriteLn "MyMax one ", X
    return X

function MyMax (X : ordered; ...) return ordered is
    result := MyMax(...)
    Write "MyMax more ", X, " and ", result
    if result < X then
        result := X
    WriteLn " is ", result

K : integer := MyMax(1, 2, 3, 4)
M : real := MyMax (1.5, 7.9, 8.43)

WriteLn "K=", K
WriteLn "M=", M

While this example shows all the arguments of the same type they need not be as in the Write and WriteLn library functions:

to Write(F : file; W : writable; ...) is
// ------------------------------------------------------------------------
//   Write a writable and something else to a file
// ------------------------------------------------------------------------
    any.Write F, W
    any.Write F, ...

Maybe studying the implementation of variadic generics in the xl2 compiler will help.

Varriount commented 8 years ago

As far as syntax goes, why not simply reuse the varargs metatype? It's not as if a generic parameter list is actually restricted to typedesc arguments (see array constructors).

Araq commented 8 years ago

The examples are all trivially implementable with a macro and/or varargs[T, conv].

Varriount commented 8 years ago

@Araq but there are still things like matrices and other areas that would benefit from variadic generic types.

Araq commented 8 years ago

It should be easy enough to use tuples and the getType API in these cases though. Somebody needs to write this code and demonstrate what problems it causes.

seankhl commented 8 years ago

@Araq, does your method allow for taking a variable number of template parameter constants (say, ints) and generating an array of function pointers from a template function with them? E.g. in C++:

template <int o>
int offset(const int i)
{
    return i - o;
}

template <int... Offs>
void make_funcs()
{
    std::array<std::function<int(int)>, sizeof...(Offs)> offs{ offset<Offs>... };
    // [...]
}

Pardon me if it's obvious to do this with compile time functions in Nim, but I'm curious, because this sort of pattern heavily simplifies metaprogramming for me.

lightness1024 commented 6 years ago

variadic generics would help the createThead proc. now the startable procs have an arbitrary arity of one.

Araq commented 6 years ago

The benefits are tiny, Nim has tuples, you can pass a tuple to thread proc.