Maybe a loaded question but what is the goal of this thread? Is it to
establish whether or not generics impact readability? In that case it
should get a lot more civil and charitable on both sides.

Anyway, my take on that: The examples mentioned, in a very real way, are
not really suitable to discuss that question. Any readability impact comes
not so much from simple declarations, but from a) how frequent
type-parameterized objects are going to be and b) how often we can omit the
type-parameteres. The issues are things like parameterized type-parameters
(today this example
<https://twitter.com/MuseumOfTypes/status/428302745330651136> flew through
my twitter stream, to illustrate the point) and extra layers of abstraction
(like using a Map<Iterable<rune>, Numeric> instead of a map[string]int).

Basically, we have three opposing forces: 1) How powerful the generics
implementation is, that is what are the things that can be parameterized,
2) How powerful type-inference is for them, that is in which specific
circumstances types can be omitted (this is the vital "readability" part)
and 3) How simple the description of them is, that is how easy is it to
understand failed type-checks to the programmer and how much space would
they take up in the spec and/or implementation.

Currently, Go *mostly* has 1 near zero (it is a little positive due to the
existence of map, [], chan… and append/copy/…), in preference of 2 and 3.
Most people agree, that 1 should get a little more love though. It's easy
to come up with syntax or semantics that make 1 large, but the issue is,
that while we want to increase 1, we don't just want to neglect 2 and 3.

Most languages with powerful generics will also include a lot of machinery
for 2, that is a complicated type-inference mechanism. Because it's so
complicated, they will mostly omit 3, that is they will not specify how
exactly it works and leave that up to the implementation, giving them the
flexibility to tune the intelligence over time. Most of them (*cough* C++
<https://codegolf.stackexchange.com/questions/1956/generate-the-longest-error-message-in-c>
*cough*) also completely fail to provide meaningful error messages for even
reasonably simple failures.

Now, it's easy to just write down *some* generic (or not generic) code to
illustrate some level of readability. But to actually see the effects, a
lot more and realistic code is needed and we *need* to talk about 2 and 3.
An incredibly good example for how to discuss these is Ian's Proposal for
type parameters
<https://github.com/golang/proposal/blob/master/design/15292/2013-12-type-params.md>.
It gives a detailed description of the power, the type-inference mechanism
and the complexity of implementation. AIUI, it failed because of 3.

Not every message or opinion about this, of course, needs this level of
detail. But just ignoring the complexity is oversimplifying and doesn't do
your position a lot of favor.
A better way to talk about readability would be, to take a real piece of
code that you'd like to write generically (or predict that people would
write), take one or two of the existing (declined) proposals and write your
code down assuming it where implemented. The advantage is, that the
proposals usually are detailed enough to meaningfully talk about the
tradeoffs involved and to be sure that "the compiler can infer that" isn't
just hand-waved.

But Hot-Takes don't really help anyone.

On Fri, Aug 25, 2017 at 10:11 AM, Egon <egonel...@gmail.com> wrote:

> package tree
>
> type Node<$Entry> struct {
> Value $Entry
> Left  *Node<$Entry>
> Right *Node<$Entry>
> }
>
> func (node *Node) Insert(value node.$Entry) {
> var side **Node<node.$Entry>
> if node.Value.Less(value) {
> side = &node.Right
> } else {
> side = &node.Left
> }
>
> if *side == nil {
> *side = &Node<node.$Entry>{Value: value}
> } else {
> (*side).Insert(value)
> }
> }
>
> --
>
> package tree<Entry>
>
> type Entry generic {
> Less(Entry) bool
> }
>
> type Node struct {
> Value Entry
> Left  *Node
> Right *Node
> }
>
> func (node *Node) Insert(value Entry) {
> var side *Node
> if node.Value.Less(value) {
> side = &node.Right
> } else {
> side = &node.Left
> }
>
> if *side == nil {
> *side = &Node{Value: value}
> } else {
> (*side).Insert(value)
> }
> }
>
>
> On Thursday, 24 August 2017 20:08:16 UTC+3, mhh...@gmail.com wrote:
>>
>> Why would you put generics on a method ?
>>
>> The syntax you demonstrate is horrible, indeed.
>>
>> what if generics are type related
>>
>> type notFinal struct {
>>    p1 <T1>
>>    p2 <T2>
>> }
>>
>> func (n notFinal) whatever(in <T1>) string {
>>    return fmt.Sprintf(in) // anything to interface{}, works.
>> }
>>
>> type Final notFinal<int, string>
>>
>> Final.whatever(1) // "1"
>>
>> //notFinal not instantiable, not type assertable
>>
>>
>>
>> Or func related
>>
>> type notFinal func(in <T1>) string
>>
>> func Final notFinal<int>
>>
>> Final(1) // "1"
>>
>>
>> That said, ultimately, the more the syntax is parametrized the more
>> complex it become. when there are many func signature as you demonstrate,
>> it will get worse.
>>
>> Named type might help, could be vetted too ?
>>
>> Also
>> none of this is as powerful as code gen.
>> None of those examples are better than interface{}.
>>
>> On Thursday, August 24, 2017 at 5:14:58 PM UTC+2, JuciÊ Andrade wrote:
>>>
>>> A lot of people like Go because code is very readable even for beginners.
>>>
>>> func f(x, y int)
>>>
>>> f is a function that receives x and y as int parameters, returning
>>> nothing. Simple enough.
>>>
>>> func f(x, y int) int
>>>
>>> f is a function that receives x and y as int parameters, returning yet
>>> another int. Fine.
>>>
>>> func f(x, y int) (z int, err error)
>>>
>>> f is a function that receives x and y as int parameters, returning two
>>> values: a first int, that we name z and an error named err. A little bit
>>> weird, but ok.
>>>
>>> func (r MyType) f(x, y int) (z int, err error)
>>>
>>> f is a method for a value of type MyType, henceforth named r, that
>>> receives x and y as int parameters, returning two values: a first int, that
>>> we name z and an error named err. Definitely not so simple.
>>>
>>> <genType1, genType2> func (r genType1) f(x, y genType2) (z getType2, err
>>> error)
>>>
>>> You must be kidding. STOP RIGHT THERE!
>>>
>>> --
> 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.

Reply via email to