best practices for generic constant in crystal lang - crystal-lang

How to define constants depended on generic type parameters in a generic class/struct, or any other way to allow sharing instantiated constant between instances of the class instantiated by the same type argument?
Like this
class Generic(T)
CONST = [] of T
end
I also tried class variable but seems not to work, which simply bound on uninstantiated type Array(T).
class Generic(T)
##const = [] of T
end

You cannot for now because it would be ambiguous what you refer to with Generic::CONST then.
See for a discussion on this related to aliases in the following issue and it associated ones: https://github.com/crystal-lang/crystal/issues/1920

Related

Binding times for template variables

In C++ for a template T variable for a class.
What would it's binding time be?
I'm thinking compile time because it would need to know what value is being passed to it before binding it to a value/address.
Yes. You could think of templates as "class factories", the result of using a template is a class that has been specialized for the specific types you use in the template. So this is all compile-time specialization.

Automatic template deduction when lhs reference is used

I was wondering if I write something like this:
Type &var = database.get<TYPE>(name);
Assuming that database is a container able to store datablocks of different datatypes. To get a reference to that datablock, the name as std::string is passed to get() so that at different places with that call I have a way to access certain 'global' variables. I have get() as a template method and I would like to keep it that way.
What I want to do is shorten that call an elegant way like this:
Type &var = database.get(name);
So the template deduction is automatically performed. Now I could create a macro for that, but this is not what I want to do, as I do not consider it elegant for such case.
That deduction though does not work, because we need a template parameter. Why can't the compiler take what is set for the variable and pass it as template parameter automatically? Is there a way to do this? I don't want to have any type conversions in this case. Can we omit it?
No, you can't do this---the rules of the language simply don't allow the compiler to take into account the declared type of var in order to perform the deduction. (Note that template arguments for a function template can be deduced when initializing a function pointer by taking the address of a function template. However, that's not what's happening in this case.)
However, you can easily avoid writing the type twice or inducing any undesirable conversions, by using auto:
auto& var = database.get<Type>(name);
Sorry, this is not possible. What you are trying to do is to have the return type of a templated function based on the value of its parameter.
This cannot work.
Automatic template deduction (like you mentioned) can only be performed, if the template parameter is obvious. For example:
template<_T> void func(_T param) { }
This can be called like
int a;
func(a); //instead of func<int>(a);
here the compiler knows exactly what you are trying to do.
Because all templates are resolved at compile time, there is no way of changig a methods return type based on any vague arguments.
You could have a look at boost::any, which does your Job quite well.

(Can I minimize the) Footprint of template in my C++ Code?

I have a large class which basically handles one buffer of variable (numeric) datatype. So it seems a good choice to use a class template with this datatype as the only parameter. I'm not experienced in C++ and I wonder/worry a bit about the "footprint" such a template makes in my code.
There are three implications of templates which in my (C++ unexperienced) eyes are not necessary and make code ugly. I tried to avoid them, but neither did I find a good example how to do it nor did I manage to find it out by myself.
So the goal of this question is: Can you either confirm the following statements or give a counterexample?
When using a class template, all class methods have to go into the header file. Even if they have no templated type in their interface or implementation.
When using a static method or member of the class, I always have to specify a template parameter (MyClass< double > :: MY_STATIC), even if the templatization does not affect any of the static properties of the class.
When using the class as a parameter for a function, I always have to give a template parameter, even when this function does not access any of the templated members? (function myFunc(MyClass< double> & myClass){ do something } )
As a general rule, don't have functions/data members in a template class which does not use the template parameters. Have a base class, put all non-template related things there, your template class should derive from it.
To answer your questions:
yes, everywhere where you need to instantiate the template, you need to see the full definition of the class and it's functions
yep, but put that into the base class
yes, see above
EDIT: One of the reasons to move to base class is code bloating (this expression actually exist, you can google it for more info): If you don't move the template unrelated code to a base class, the very same template independent code will be copied for all instantiation of your template, which means a lot of unnecessary code. If you put it to a base class, you will only have this code once.
Yes. On the plus side, the code is only generated when the metod is actually used for the specialization.
Yes. However, there is no (other then design choice) need for a static method to be a memeber of the templated class if it has no use for the templated parameter.
Yes. The size and memory layout of the structure is determined by the template parameter.

How to construct custom type in a template class definition

Is it possible to use templates to costruct types in the type definition? E.g. I would like to have something like this:
class MyType
{
template<typename T>
someNamespace::T Convert(someOtherNamespace::T value);
};
If templates cannot be engaged for this purpose, is such a declaration even possible?
Regards, Dawid
No, it's not. Template parameters name actual types, not identifiers (which you would need if you wanted to do lookup in a namespace).
Also, I don't see how this is particularly useful. It requires that two namespaces contain types that have the same name and can be converted in a completely generic manner - how often will you see that?
Can you describe in more detail what you want to do?
Not really sure what you want, but maybe following (using macro) may help:
// Assuming value is of type someOtherNamespace::identifier
#define CONVERT(identifier, value) static_cast<someNamespace::identifier>(value)

Why are structs not allowed in template definitions?

The following code yields an error error: ‘struct Foo’ is not a valid type for a template constant parameter:
template <struct Foo>
struct Bar {
};
Why is that so?
template <class Foo>
struct Bar {
};
works perfectly fine and even accepts an struct as argument.
This is just an artifact of the syntax rules - the syntax just lets you use the class or typename keywords to indicate a type template parameter. Otherwise the parameter has to be a 'non-type' template parameter (basically an integral, pointer or reference type).
I suppose Stroustrup (and whoever else he might have taken input from) decided that there was no need to include struct as a a keyword to indicate a type template parameter since there was no need for backwards compatibility with C.
In fact, my recollection (I'll have to do some book readin' when I get back home) is that when typename was added to indicate a template type parameter, Stroustrup would have liked to take away using the class keyword for that purpose (since it was confusing), but there was too much code that relied on it.
Edit:
Turns out the story is more like (from a blog entry by Stan Lippman):
The reason for the two keywords is
historical. In the original template
specification, Stroustrup reused the
existing class keyword to specify a
type parameter rather than introduce a
new keyword that might of course break
existing programs. It wasn't that a
new keyword wasn't considered -- just
that it wasn't considered necessary
given its potential disruption. And up
until the ISO-C++ standard, this was
the only way to declare a type
parameter.
Reuses of existing keywords seems to
always sow confusion. What we found is
that beginners were [wondering]
whether the use of the class
constrained or limited the type
arguments a user could specify to be
class types rather than, say, a
built-in or pointer type. So, there
was some feeling that not having
introduced a new keyword was a
mistake.
During standardization, certain
constructs were discovered within a
template definition that resolved to
expressions although they were meant
to indicate declarations
...
The committee decided that a new
keyword was just the ticket to get the
compiler off its unfortunate obsession
with expressions. The new keyword was
the self-describing typename.
...
Since the keyword was on the payroll,
heck, why not fix the confusion caused
by the original decision to reuse the
class keyword. Of course, given the
extensive body of existing code and
books and articles and talks and
postings using the class keyword, they
chose to also retain support for that
use of the keyword as well. So that's
why you have both.
You can instantiate a template using a struct; however, the syntax for declaring a template type only allows the keywords "class" or "typename" to appear where you are attempting to use the keyword "struct".
I should add that you can also use a specific type (e.g. int), if you want to instantiate your template based on a compile-time constant or based on an object with external linkage... but that's somewhat of an aside.
The short answer is: template <class Foo> even accepts a union or a double - still, neither is allowed instead of class. However, typename is. That's just the way the syntax was defined.
A somewhat longer answer: When templates for C++ where "invented", there was a keyword needed at that place saying that the next identifier would be a type name. It was decided to re-use the existing class keyword. That was a bit confusing, but there's a general reluctance to introducing more keywords, because they always break some existing code which used this as an identifier when it wasn't a keyword.
Later, typename became a keyword for other reasons, and since it is a much better fit, it can now be used in that place: template <typename Foo>. However, with billions of lines of code out there using class in that place, it must remain valid for that purpose. So now both are allowed.
As is common in C++, this created several camps as to what keyword to use in that place. Some stick with class, because they've been using it for more than a decade. Others prefer typename, because it's a much better fit. Some use class when Foo is expected to be of a class type (members are accessed) and typename when built-ins can be used, too.
Because the keyword for template parameters is class or typename. This doesn't restrict the Foo parameter to be a class - it can be of any type.