Probably the most famous variadic function is printf in C, which can take an variable number of arguments. Is there a way to assign a type to printf in ATS? In general, can variadic functions be typed in ATS?
Some work was done to accomplish this around the time of the ATS2 0.3.8 release. A simple example of a typed variadic function in ATS is found here.
By mimicking this example, yes, one can have typed variadic functions in ATS. Currently, however, it appears that unpacking the list of variadic arguments within ATS code itself is not possible. In the example linked above, we use inline C code to get around this limitation.
Related
I recently came across the topic of C++11 variadic templates, and I'm wondering in what situations are they actually used? Are they primarily intended for recursion, where the number of parameters can vary (or is unknown)? Are there any other use cases apart from recursion?
A good case for variadic templates is emplace (and emplace_back, emplace_front et.al.), i.e. constructing an element of a container in the storage the container allocated, with whatever constructor arguments the type takes.
Without that you would have to copy or move an existing object into that storage.
E.g.
std::vector<std::string> strings;
strings.emplace_back(10, 'a');
More generally, whenever you have something that wants to pass along arguments it was given to an expression that can take varying amounts of parameters, you'll want to use a variadic template.
I have a method in Golang that requires a []*type as a parameter.
I have a slice:
s := make([]myType, 3)
How do I do that?
In short (and as somewhat alluded to by other commenters), it sounds like you're asking how to use a feature that Go doesn't support. Namely, generics: a function with signature []*type, where type isn't actually a specific concrete type that you've already defined. While this might be supported in the future, it isn't for right now - you're stuck with defining the function with []*specific-concrete-type for now.
In Julia, I most often see code written like fun(n::T) where T<:Integer, when the function works for all subtypes of Integer. But sometimes, I also see fun(n::Integer), which some guides claim is equivalent to the above, whereas others say it's less efficient because Julia doesn't specialize on the specific subtype unless the subtype T is explicitly referred to.
The latter form is obviously more convenient, and I'd like to be able to use that if possible, but are the two forms equivalent? If not, what are the practicaly differences between them?
Yes Bogumił Kamiński is correct in his comment: f(n::T) where T<:Integer and f(n::Integer) will behave exactly the same, with the exception the the former method will have the name T already defined in its body. Of course, in the latter case you can just explicitly assign T = typeof(n) and it'll be computed at compile time.
There are a few other cases where using a TypeVar like this is crucially important, though, and it's probably worth calling them out:
f(::Array{T}) where T<:Integer is indeed very different from f(::Array{Integer}). This is the common parametric invariance gotcha (docs and another SO question about it).
f(::Type) will generate just one specialization for all DataTypes. Because types are so important to Julia, the Type type itself is special and allows parameterization like Type{Integer} to allow you to specify just the Integer type. You can use f(::Type{T}) where T<:Integer to require Julia to specialize on the exact type of Type it gets as an argument, allowing Integer or any subtypes thereof.
Both definitions are equivalent. Normally you will use fun(n::Integer) form and apply fun(n::T) where T<:Integer only if you need to use specific type T directly in your code. For example consider the following definitions from Base (all following definitions are also from Base) where it has a natural use:
zero(::Type{T}) where {T<:Number} = convert(T,0)
or
(+)(x::T, y::T) where {T<:BitInteger} = add_int(x, y)
And even if you need type information in many cases it is enough to use typeof function. Again an example definition is:
oftype(x, y) = convert(typeof(x), y)
Even if you are using a parametric type you can often avoid using where clause (which is a bit verbose) like in:
median(r::AbstractRange{<:Real}) = mean(r)
because you do not care about the actual value of the parameter in the body of the function.
Now - if you are Julia user like me - the question is how to convince yourself that this works as expected. There are the following methods:
you can check that one definition overwrites the other in methods table (i.e. after evaluating both definitions only one method is present for this function);
you can check code generated by both functions using #code_typed, #code_warntype, #code_llvm or #code_native etc. and find out that it is the same
finally you can benchmark the code for performance using BenchmarkTools
A nice plot explaining what Julia does with your code is here http://slides.com/valentinchuravy/julia-parallelism#/1/1 (I also recommend the whole presentation to any Julia user - it is excellent). And you can see on it that Julia after lowering AST applies type inference step to specialize function call before LLVM codegen step.
You can hint Julia compiler to avoid specialization. This is done using #nospecialize macro on Julia 0.7 (it is only a hint though).
I have a class that's using an std::discrete_distribution which can take an std::initializer_list OR a couple of iterators. My class is in some ways wrapping the discrete_distribution so I really wanted to mimic the ability to take an std::initializer_list which would then be passed down.
This is simple.
However, the std::initializer_list will always be constructed through some unknown values. So, if it was just a std::discrete_distribution I would just construct from iterators of some container. However, for me to make that available via my class, I would need to templatize the class for the Iterator type.
I don't want to template my class because it's only occasionally that it would use the initializer_list, and the cases where it doesn't, it uses an std::uniform_int_distribution which would make this template argument, maybe confusing.
I know I can default the template argument, and I know that I could just define only vector::iterators if I wanted; I'd just rather not.
According to the documentation, std::initializer_list cannot be non-empty constructed in standard C++. BTW, it is the same for C stdarg(3) va_list (and probably for similar reasons, because variadic function argument passing is implementation specific and generally has its own ABI peculiarities; see however libffi).
In GCC, std::initializer_list is somehow known to the C++ compiler (likewise <stdarg.h> uses some builtin things from the C compiler), and has special support.
The C++11 standard (more exactly its n3337 draft, which is almost exactly the same) says in §18.9.1 that std::initializer_list has only an empty constructor and refers to §8.5.4 list-initialization
You probably should use std::vector and its iterators in your case.
As a rule of thumb and intuitively, std::initializer_list is useful for compile-time known argument lists, and if you want to handle run-time known arguments (with the "number" of "arguments" unknown at compile time) you should provide a constructor for that case (either taking some iterators, or some container, as arguments).
If your class has a constructor accepting std::initializer_list<int> it probably should have another constructor accepting std::vector<int> or std::list<int> (or perhaps std::set<int> if you have some commutativity), then you don't need some weird templates on iterators. BTW, if you want iterators, you would templatize the constructor, not the entire class.
I've obtained a function pointer at run-time, let's say through something like GetProcAddress (so a weakly-typed void*), and then I've got this metadata that tells me what the function's signature is at run-time. How can I call the function correctly, preferably in Standard code? C++0x solution is fine, and I don't mind having to enforce my own type-safety.
Er... no, you can't. There is no thing like reflection is C++ or C++0x, you can't get a type out of a string or whatever. Unfortunately :)