I am in the middle of implementing a generic tree type as part of a CLI 
flags/configuration package, and a key goal in my design is to make the 
declarations it parses as easy to read as possible, and as far as possible, 
avoiding too much boilerplate. 

Yes, nothing new there, but in the process, I have noticed something that 
isn't at the top of people's minds when they think of generic data types: 
validation

Actually, default values is another aspect of generics as well, because a 
generic type also has to have some kind of valid new/empty state, to stay 
consistent with the way that the builtins are always zeroed before use, but 
I'll address the former first.

Well, ok, let's just say that implementation of generic structures, (which 
implicitly aren't very generic in implementation), works with the 
interface{} container, which is a very limited Set structure, with one 
implicit function that when satisfied makes the variable it encapsulates 
recognised as a complete implementation and permits interchange with other 
implementations' type.

So, in Go, this means (and same in all languages though they sugar coat it 
in various automatic stuff) that before you can call methods on a generic 
type, the contents of the variable have to be checked. 

>From where I am at right now, this is of course my job as the programmer to 
write these. However, my reason for all the rambling up to this point is 
that I think that since validation is mandatory for dynamic types, that the 
proposed generics syntaxes that are under consideration should include 
constraint/contract type validation. For this, then there must be a 
constructor and a bounds/validation function that ensures that its methods 
will find everything that must be there, where it must be, preferably 
before the main() is invoked.

On the latter subject, well, I think I already covered that - just simply 
that when you declare a new type, all zeroed may not actually be a valid 
new and empty variable. The specifics of a type may mean that certain 
things must be in certain places, and the things that are in the container 
are valid members of the set of possible contents and that these members 
contents are not outside of the bounds that would lead to bugs.

It does lead me to a thought about a go-idiomatic style of generic type, 
however - and it all centers around the type declaration syntax. Not all 
generics are going to need something other than the standard zeroing, so 
the initialiser function need not be mandatory. This is starting to blend 
in an unseemly way into some parts of OOP with the concept of a constructor 
(go dodges the need for destructors mostly, but I would suppose in 
implementation a destructor might be a good idea especially for resources 
that need freeing manually).

Actually, right there might be another issue that might be important with 
generics, but more generally - if there could be some way to tag a type 
such that unless you specify otherwise, it runs its closer on implicitly on 
close of the function scope it lives in, and this also suggests that some 
means of indicating this relationship between two methods would also make 
sense.

So, taking stock, I am saying that a consistent Go styled generic would 
need to have builtins for initialisation to valid empty state, one for 
freeing resources locked up during lifecycle, and some way of specifying a 
valid range off values for the type.

When you really look at it, implementing generics basically means code 
generation involving a lot of reflection, or, the likely and better option, 
that compilation creates tagged sets for every type defined in a package, 
so that these attributes are available without the expensive parsing of the 
metadata tied up in the symbol table. If my surmise is correct, it means 
that creating a complete generics syntax for Go also means creating 
constructors, destructors, validation/sanitising, and adding the necessary 
metadata to be efficiently accessible at runtime instead of parsed out of 
linker metadata.

It also brings up the issue that there is a more than subtle connection 
between generic types and exception/error handling, with regard to 
validation, the construct required for this is structurally similar to 
error handling, in that, already I have described initialisation, 
deallocation, and validation, all of these are states, and in 
implementation it means that one should consider carefully whether there is 
other things that seem at first blush, peripheral, but should be considered 
indispensible...

Namely, the error value. 

I thought a lot about this in the last few weeks, and I had already in 
practise experimented with creating pipeline-pattern types using 
interfaces, in which the error was inside the struct containing the 
variable data (byte slice in this case), and the interface included several 
methods relating to the examination, setting and resetting of the error 
value. I didn't quite get to fully codifying in my mind exactly what was 
mandatory and what you will regret not putting in there (to prevent edge 
cases and potential injections).

Think about the situation with the basic, machine-level built-in types. Do 
ints and floats have an error value? Superficially, one might say 'no' 
based on what is specified in the Go language definition. But this is 
entirely incorrect. These types are implemented mostly 100% directly in the 
CPU, and every operation involving them can affect the Condition Code 
register. Normally this state information is transparently part of the 
various comparison operators, but I can see how it would make a lot of 
sense if you could interrogate these variables and get some representation 
of the CC, and that this metadata would have to be part of any error 
handling scheme added to the language.

And then, if we expose this data in these base types, logically the 
metadata for errors in compound, especially generic types, has a further 
set of type-specific states. This also could help a lot with both error and 
generics handling, for example, one of the flags could indicate that the 
last thing done to the variable was being zeroed. For some purposes, 
receiving an unmodified fresh variable could be written in as a constraint 
in the function header, so you would have !nil and !zero constraints on a 
generic method parameter, and, well, I'll just finish on this last point - 
a lot of error handling becomes irrelevant when you can concisely specify 
constraints on a parameter's values and states, that cuts it off at the 
pass.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to