Open ajusa opened 2 years ago
Not to diminish the proposal, but generic aliases kind of work in the example case, although this is likely buggy and could be too impractical for most purposes.
type
Language = enum
English
German
LanguageString[L: static Language] = string
english = LanguageString[English]
german = LanguageString[German]
proc checkValid(str: english) = echo "got english"
proc checkValid(str: german) = echo "got german"
var text = "hello! ".english
text &= "how are you?".english
checkValid text
checkValid "hallo".german
Obviously this is just a hack to add a layer of indirection to trick the overloading mechanism and generics might not be applicable to every case. This is just the closest thing I can think of to adding "tags" to types (like string {.tags: [English, GrammarChecked].}
) and a simple weak distinct mechanism would be useful enough.
Why not type english = string
then?
Why not
type english = string
then?
proc checkValid(str: english) = discard
proc checkValid(str: german) = discard
Is why not, aliases should not allow the above to happen. They want to easily be able to have a distinct type that allows them to implement custom behaviour without having to manually borrow everything. This means you can use english
in place of string
but not string
in place of english
.
@beef331 recommended I open an RFC for my use case, so here's an attempt at describing what I think would be nice to have. First time writing an RFC, please let me know if something isn't clear!
Problem
So technically, Nim has a way to solve the issue outlined above - just use the borrow pragma. Adding this line fixes the issue:
This is a bit painful once you start wanting to define more and more procs for your distinct type, which leads to lots of extra code. When writing this RFC, I had to look up the exact type definition and proc for appending to a string, as I forgot the first argument needed to be a
var string
. Nim further recommends that if you are doing this for a numeric type, just create a set of templates that will borrow most of the relevant procs for you, to avoid code duplication.A lot of the time I create a distinct type though, I want the existing operations of the base type, but I want the type safety of not being able to use the base type for my procs. Eg, the following example is usually why I want a distinct.
Keep in mind that is my use case - others use distinct for different reasons, but the proposal here shouldn't affect them.
Why not just use converters? Well adding
doesn't fix the issue.
If you want to borrow all of the operations of the base type of a distinct, then why not use type aliases?
Proposal
Extend the borrow program within a type definition to borrow all of the procs of the base type. The example from above would be rewritten as
This improves type safety and clarity over using type conversions everywhere (eg converting both arguments to string for the append, then converted both into english). Additionally, this proposal doesn't have any breaking syntax or new syntax - it's still just a pragma.
Nim already has this defined for accessing fields of the base type when using distinct:
{.borrow: `.`.}
in the type definition. This proposal is just an extension to that pragma, allowing access to all the procs of the base type as well.