This is something that I have seriously considered to be the right way for 
Go to express other generic types. I am in fact in the middle of a project 
at the moment where I have created a pair of generic byte buffer types, one 
is the regular kind, the other uses memguard locked buffers, for keeping 
secrets out of reach of other processes on a system.

A lot of the complaints that lead to the idea of creating a generics system 
in Go tend to start from the absence of a few basic types. One is the set, 
and in particular the union operator. However, it is trivial to implement 
various types of sets and set operations based on maps or slices, and more 
often than not you save absolutely no time predeclaring a framework when 
you can just embed a number of other structs inside a type as well as by 
implementing or composing in interface implementations.

But knowing from having done quite a bit of study of data structures, being 
one of my favourite subjects, that one-size-fits-all only really happens in 
a very small number of cases. Hash table indexes like used to make maps, 
arrays and slices, but binary trees, since someone mentioned it, these have 
many different forms, as dictated by their application. You have heaps and 
you have trees, the former are better for queues and the latter for 
optimising searches. There is several ways to implement them. You have 
B-trees, btrees, red/black, B-heaps, AVL, and so on and so on. These are 
not really subject matter for basic language types, though the language 
might improve their use and readability with a number of special keywords 
and declaration types.

I think that the solutions to most of the problems lies in embedding error 
status into every type (except maybe machine-sized integers), a conditional 
return statement that allows you you to handle errors concisely within a 
statement block, and possibly some kind of built-in addition, in addition 
to the universal error status flag, which integrates some kind of 
configurable serialisation function for wire and storage. There is many 
options already available, but to make it simpler to invoke 'freeze' and 
'thaw' functions, which provides a data format that can optionally contain 
type metadata and enable this data to become, no matter what its' type, an 
object that any other function can pass around and as required see and 
access parts of the data that relate to the interface.

Very small changes, is what I am suggesting. Implicit error type in all but 
integers, a conditional break/return function (probably one for each) and 
more generally what I am suggesting is extend the built in 'error' 
interface to add set, unset and serialise/deserialise functions. And maybe 
a built-in structured logger that lets you track the state of all variables 
as each function operates on it, but only automatically in case of throwing 
an error.

I think that go almost already perfectly implements the generic type 
[]byte. Everything can be turned into []byte and []byte can encode any 
other variable.

Go is absolutely a leader in the programming language field. I just saw 
yesterday a blog post about 'new features in C++17' or whatever, 'that 
simplify your code'. Every single feature already in Go, the optional first 
statement in the 'if' structure, type inference through assignment to 
constants, and somethting else I forget. In every area of the core 
language, Go uses a pattern that is both simpler and more powerful than you 
find in most other languages, and that can trivially express many other 
patterns usually in a far more concise yet readable manner.

The changes for version 2, in my opinion, should first identify the real 
meat of the issues that people point at their previous language experiences 
to talk about, but go far deeper to decisions about syntax that are in many 
cases now quite obsolete concerns. In the old days, every byte was so 
expensive. The price is very low now and basically seems to be flattening 
out, so people are slowly starting to realise that certain conventions were 
only based on this bit-conservation.

Another issue has to do with creating brittle codebases with excessive need 
for copy and paste to implement something where in each instance the code 
only differs by the type of only one variable, that is functionally the 
same only differing in such as the number of bytes it can encode, sign, or 
any arbitrary number of other groupings of elements. Go's interfaces and 
embedding go a long way to neaten this up but this really is at the centre 
of what needs to be improved, and before anyone actually changes the 
language, explore the ways of expressing the pattern in go to see if the 
solution might just be idiom rather than syntax. Most of Go's idiom has 
been quite certain and settled and you don't take long to see by violating 
it what extra work and complexity you create. I have pretty high confidence 
in the Go Authors rejecting all but the simplest, and most expressive 
solutions, and favouring the codification of idiom when just using the 
right pattern gives all the benefits that extra complexity of syntax is 
being proposed for.

On Thursday, 20 September 2018 02:19:05 UTC+2, Randall O'Reilly wrote:
>
> Given all the challenges associated with generics, it might be productive 
> to follow up on this alternative approach of identifying a (small set) of 
> new primitive containers and functions that would otherwise have been 
> written using generics, that are of sufficiently general applicability as 
> to merit inclusion in Go2?  I know this kind of discussion is had 
> frequently on this list, e.g., recently in the case of tuples and ternary 
> expressions, and the outcome is usually a pretty convincing “not gonna 
> happen”, but MAYBE in the light of the generics discussion there might be 
> some fresh insights along these lines? 
>
> It seems like one of the fundamental reasons generics are so “contrary” 
> for Go is that they require exposing a bunch of low-level internal 
> special-case logic (e.g., operator semantics, etc) in a “meta” explicit 
> way.  Doing so in a clean, simple, elegant way may be impossible.  The 
> current Go1 alternative strategy is to bury all that logic well 
> out-of-sight and provide a simple, elegant “magic” set of language 
> primitives that seamlessly interoperate with all the other basic types. 
>  For those things that are supported in this way, the result is pure joy 
> and simplicity :)  So, a logical alternative to generics is to think about 
> anything of sufficient generality that is missing, and just add it in with 
> the same kind of existing magic. 
>
> Another way of framing the issue is: if you give people generics, they 
> will each write the same kind of functionality in slightly different ways. 
>  Instead, the “Go” way is to figure out the *best* way to do something, and 
> build that right on into the language as a primitive, which fully 
> interoperates and deals with all the necessary idiosyncrasies of the other 
> types.  I doubt anyone would argue that the existing “minimal basis set” of 
> functionality is truly minimal and truly covers the vast majority of needs. 
>
> The list of plausible additions is likely quite small, and the draft 
> generics proposal suggests what most of these might be: 
>
> * binary trees (llrb?) — can anyone really argue AGAINST this? 
>
> * sets — really map[T]struct{} seems fine here — probably not worth it? 
>
> * linked lists??  probably not given llrb?  also I’ve written many stacks 
> and they seem trivial and painless using slices.. 
>
> * tensors (n-dimensional arrays) — this would be GREAT for numerical stuff 
> — there is an existing heroic implementation 
> https://github.com/gorgonia/tensor but a minimal core builtin support for 
> the basic slice-level functionality extended to multiple dimensions would 
> be really nice!  Here’s a proposal: 
> https://go.googlesource.com/proposal/+/master/design/6282-table-data.md 
>
> Functions: 
>
> * insert() primitive for slices — I wasn’t able to find prior discussion 
> of this, but this is the ONLY major pain point for me in dealing with 
> slices — it is 3 repetitive, relatively opaque lines of code every time, 
> and seems well worth the “investment” in a new keyword..  I did find some 
> debate about whether delete() should operate on slices too — seems like 
> that would be a simple semantic convenience that makes code more explicit 
> and the counter-arguments from the previous debate weren’t that strong IMO 
> https://grokbase.com/t/gg/golang-nuts/1366rkp7ef/go-nuts-why-not-provide-a-delete-function-in-slices-just-like-in-maps
>  
>
> * max(), min(), abs() — how about it?  these seem like the main focus of 
> generics discussion, and are a “safe” special case form of the ternary 
> operator.  When I first found out that there wasn’t a max operator for ints 
> in Go I was really shocked.. I got over it, but still, these are really 
> basic mathematical operators that I use all the time.. 
>
> * most of the other examples in the generics proposal seem like such 
> trivial one-liners (sorting, map / reduce, the various channel functions) 
> that it doesn’t quite seem worth it…   
>
> Anyway, that is really it for my list — if these were in the language, it 
> would make my code easier and simpler to write and understand.  I’m not 
> sure I could say the same for any of the existing generics proposals.. :) 
>
> - Randy 
>
> > On Sep 18, 2018, at 2:05 PM, Michael Jones <michae...@gmail.com 
> <javascript:>> wrote: 
> > 
> > I believe average Go code will be better if there are map-quality llrb 
> trees, stacks, sets, ... for the taking, just as if tuples were a first 
> class thing. There were horrors in STL's evolution, but by now, everyone 
> gets such data structures right the first time they use them, just as they 
> do now with Go maps. 
> > 
>
>

-- 
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