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.