On Mon, Feb 25, 2019 at 3:06 PM Louki Sumirniy <louki.sumirniy.stal...@gmail.com> wrote: > > 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.
Have you seen the contracts draft? This addresses the validation issue you raised, in compile time: https://go.googlesource.com/proposal/+/master/design/go2draft-contracts.md With lots of feedback and alternative suggestions: https://github.com/golang/go/wiki/Go2GenericsFeedback > > 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. -- 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.