Some languages support Generic Constraints (C#, Typescript, even Python). This allows you to write generic functions/classes where you have some knowledge about the generic parameter and want to use it.
While v doesn't support subclassing, it does have interfaces, which means we can still benefit from this concept.
Any chance of this being supported?
Would static assert (i.e. compile time assert) be enough? Or do I miss something about the semantics behind "Generic Constraints"?
Not sure exactly what you mean...
The idea is an ability to constrain generic parameters, so you can utilize some preexisting knowledge about the structure of the generic.
A derivative example from TS (pseudo syntax):
interface Lengthwise {
length int
}
fn logging_identity<T extends Lengthwise>(arg T) T {
println("$arg.length") // We know it has a .length property, so no error
return arg
}
Full explanation and example: https://www.typescriptlang.org/docs/handbook/generics.html#generic-constraints
Oh, after reading the following from the URL you linked, I understood what you mean.
In our loggingIdentity example, we wanted to be able to access the .length property of arg, but the compiler could not prove that every type had a .length property, so it warns us that we can鈥檛 make this assumption.
Actually, I never thought that someone could "bend" the semantics generics so much, that you would need to provide an additional functionality (apparently called "generic constraints" in TS and maybe others) to allow the use for which generics were invented.
From my understanding V uses the generics syntax just for compile-time specialization (i.e. something similar to plain macro substitution) and won't do any type checks until the specific use of the generic method/function/routine gets fully specialized. First then types and other stuff will get checked. If my understanding is correct, then "generic constraints" are supported (though without the unnecessary explicit syntax as in TS).
Currently there is still some designing ongoing regarding generics, so @medvednikov will tell us how generics will work in the end.
Generic constraints are useful only if the language supports inheritance, because you can have a chain of types and so, you need to specify (in some cases) a restriction on generic type.
In fact if interfaces was well structured early, the only case for use generic constraint would be <T : int_1, int_2, ..., int_x> (look Rust traits). Do you really think that it would be used in V? NO, because embedded structs can represent this situation in a clear way. Complicate the syntax is useless in this case.
I'm not yet sure how it will work. I just know I want to keep it as simple as possible. It's very easy to write really unreadable stuff with complex generics options.
Right now it works like C++ templates, so no concepts. Concepts may be useful, but I need to finish interfaces first to see where this goes.
@medvednikov about types, Imho the only things we need are generic structs, embeddable structs and good interfaces (like a more powerful Go). No other syntax.
I tend to agree @LorenzoPirro
I think I might be missing something...
We can have multiple structs that implement the same method or have the same properties. And we have interfaces that can represent these structs.
Now, let's say I want to write a method that takes a struct that implements some interface and returns the same struct - how can I do that with the current design?
Some code to illustrate:
struct Arr {
length int
}
struct Dict {
length int
}
arr:= Arr{}
dict := Dict{}
new_arr := copy(arr)
new_dict := copy(dict)
new_arr should be Arr and new_dict should be Dict.
What should be the signature of copy, assuming I want to restrict the input to structs that have the length property (and possibly use this property in copy)?
What should be the signature of
copy, assuming I want to restrict the input to structs that have thelengthproperty (and possibly use this property in copy)?
I can see only 2 mutually exclusive use cases:
The body of copy() will not touch (e.g. read) the length field of the passed struct and thus I don't see any reason why would you want to constrain it.
The body of copy() will use (e.g. read) the length field of the passed struct and thus if the passed struct doesn't provide any, compilation will fail. Why would anyone want to specify anything then? I don't even get the use case of multiple inheritance mentioned above (disregarding V doesn't have inheritance).
I must be missing something really huge as otherwise I absolutely don't get this obsession with the more text written the better the result (I say no, we're not slaves of machines, we're not recreating Java ecosystem nor C++ ecosystem nor any other counter productive system - the machine must figure out what I wanted to say by leveraging a cleverly engineered interface which is the language - not by specifying everything down to the tiniest imaginable irrelevant things manually over and over).
Btw. you can always write some dummy statement like _ := passed_struct.length in copy() to transform the case (1) into (2).
Ok, thanks @dumblob for clearing things up a bit!
My two cents:
The only thing some people might want is the ability to be explicit, but that doesn't offer more functionality and is more of a philosophical thing.
From my perspective, this issue can be closed. Thanks!
Most helpful comment
I tend to agree @LorenzoPirro