>
> But I don't want to tie my users down to integers and floats. What if they
> want to sort strings? What if they want to sort complex numbers, matrixes,
> or what have you?
This is what the interface concept was made for.
Why would the implementation of IsLeft be different if the BAST data is
organized another way? I think the abstraction you're expressed isn't
narrow enough.
I don’t know the BAST details, but why not start here?
type Node struct {
Element
Left *Node
Right *Node
}
func (a Node) LeftEqual() bool {
if a.Left == nil {
return false
}
return a.Equal(a.Left.Element)
}
type Element interface {
Equal(Element) bool
Null() bool
}
Matt
On Monday, April 23, 2018 at 8:55:14 AM UTC-5, Louki Sumirniy wrote:
>
> I did look at the Red/Black tree on Github and that was what got me
> started. But you need to understand exactly why those functions seem great
> in number. First of all, of course you could swap out 3 of those
> comparators for 1, and you probably don't even get why there is the 'empty'
> one. The datatype uses zero as a null value, as it is aimed at hashes and
> pretty much nothing hashes to zero (99.99999999% to understate it).
>
> In the code the caller would have to use, and this starts with my own
> code, so I am considering my own capacity to decode my code versus writing
> it in such a way that it is simple to understand. If I collapse those three
> functions into one, I either have to define a set of constants to put a
> human readable name on it - or, for a very small cost of maybe 10-15 bytes
> extra, human can read the code and know what it does and why it isn't
> incorrect. When you look further down to see what these functions are
> actually implemented with, you'll discover they are mostly one-liners. On
> the micro scale, it might seem making separate calls for these is a waste.
> But on the other side, if my caller code has to run a 3 level or longer
> if/then or switch/case, did I, as the programmer of the library, do my
> users (my fellow programmers) any favours? Nope!
>
> With this, the user can just say 'b.IsLeft(number, cursor)'. Sure, maybe
> there is no point in even having more than two conditions, since !IsLeft is
> the same as IsRight. But what if I wanted to descend the sort order. Then
> my code is riddled with '!IsRight' while I am trying to travel left. It's
> not good for the reader, and not good to read is hard to maintain, hard to
> maintain is expensive, and probably will be replaced by something else
> later. Reusability is very important for low level functions. It would be
> better for everyone if someone did the job right, first time, and for a
> long time afterwards, everyone can depend on it.
>
> And coming back full circle to how I came up with this, it was precisely
> by reading the cryptic and difficult to understand code of others, like
> that Red/Black tree. Computer programming is a heavy cognitive load task as
> it is. Arbitrary concepts of efficiency that don't take account for the
> cost of decoding the results of this theory tend to lead to reinventing the
> wheel, because the wheel was too cryptically constructed to simply modify
> it.
>
> </rant>
>
> The IsNull function is actually just a way of implementing x == 0. But I
> don't want to tie my users down to integers and floats. What if they want
> to sort strings? What if they want to sort complex numbers, matrixes, or
> what have you? I can't overload the equality operator, and even if I could,
> then there would be the issue of type inference, implicit casts, or the
> wordiness of explicit casts. Instead, the IsNull is already typed to the
> data you want to work with, it can have something other than zero as its
> null sentinel, or in other words, my slightly wordy interface means your
> sleek, svelte application that is easy to debug.
>
> On Monday, 23 April 2018 16:25:17 UTC+3, [email protected] wrote:
>>
>> This is a code smell for me:
>>
>> type BAST interface {
>> AddRow() error
>> IsLeft(interface{}, Cursor) bool
>> IsRight(interface{}, Cursor) bool
>> IsEqual(interface{}, Cursor) bool
>> IsEmpty(Cursor) bool
>> …
>>
>> Interfaces should be small. This looks like a class definition which
>> isn’t a Go pattern. Also I would avoid interface{} if possible, and the
>> function types seem more complicated than necessary. I’m not convinced your
>> types/API are optimal.
>>
>> I still don’t exactly understand the goal, but this is my thinking about
>> the playground example: https://play.golang.org/p/KNdrYbebpuo
>>
>> Matt
>>
>> On Monday, April 23, 2018 at 3:46:03 AM UTC-5, Louki Sumirniy wrote:
>>>
>>> I spent two hours wrestling with this, but as you can see in this
>>> playground, the method I proposed totally works:
>>> https://play.golang.org/p/FMvisWS9tuP
>>>
>>> I propose that the type builtin when dealing with functions should have
>>> an extension made to it to add the method binding to the type signature so
>>> this workaround is not necessary. It would not break the spec, old code, or
>>> any of the goals that Go works towards. It would actually help with getting
>>> adoption by OOP programmers, in my view, because method overriding for this
>>> exact purpose of enabling the abstraction of backend type stuff (in my case
>>> it's just an array, but it could easily be a storage protocol or network
>>> protocol) would help immensely in implementing pluggable architectures.
>>>
>>> On Monday, 23 April 2018 08:23:24 UTC+3, Louki Sumirniy wrote:
>>>>
>>>> https://github.com/golang/go/issues/24996#issuecomment-383424588
>>>>
>>>> It seems that (Type).FuncName in the assignment binds to the struct...
>>>> I am glad I found an answer so quickly because my hackish solution was
>>>> gonna be implemented today.
>>>>
>>>> On Monday, 23 April 2018 02:20:47 UTC+3, Louki Sumirniy wrote:
>>>>>
>>>>> You will see in the code I linked in the previous message that I
>>>>> already do have the interfaces in there. They can't be bound to the
>>>>> struct
>>>>> directly because I can't specify a function type that matches the
>>>>> signature, thus the use of a wrapper, and the interface types in the
>>>>> parameters.
>>>>>
>>>>> I just can't override them, and the great bulk of the code is not
>>>>> these small set of initialiser/allocator/comparator/getter/setter
>>>>> functions, so to have to search and replace through the whole thing, and
>>>>> maintain multiple nearly identical pieces of source code for the sake of
>>>>> 7
>>>>> functions that are all very short, and differ between these versions,
>>>>> when
>>>>> everything else is the same... then I find a bug in one version, in the
>>>>> outer shell of the code and I have to merge every change of it into the
>>>>> other 5 versions... it's extremely cumbersome.
>>>>>
>>>>> The solution I have shown is just the first thing that looks to me
>>>>> like it would work. I have read tons of tutorials about composition and
>>>>> polymorphism and embedding in go, and in the end I pieced this together
>>>>> from several different things I learned. I tried several different
>>>>> things.
>>>>> It just makes absolutely no sense to have to go through and add a load of
>>>>> maintenance work to my code just so I can create, expand, read, write and
>>>>> compare values stored within the otherwise identical data structure.
>>>>>
>>>>> On Monday, 23 April 2018 01:44:43 UTC+3, [email protected] wrote:
>>>>>>
>>>>>> Interface types are useful when the data structure is varied. Why not
>>>>>> an interface containing these varying functions as methods instead of
>>>>>> function types?
>>>>>>
>>>>>> Matt
>>>>>>
>>>>>> On Sunday, April 22, 2018 at 5:20:12 PM UTC-5, Louki Sumirniy wrote:
>>>>>>>
>>>>>>> I essentially am trying to find an effective method in Go,
>>>>>>> preferably not too wordy, that lets me create an abstract data type, a
>>>>>>> struct, and a set of functions that bind to a different data type, and
>>>>>>> that
>>>>>>> I can write, preferably not in too much code, a change that allows the
>>>>>>> data
>>>>>>> type of the embedded data to be changed. It's basically kinda
>>>>>>> inheritance,
>>>>>>> but after much fiddling I found a hackish sorta way that isn't *too*
>>>>>>> boilerplate filled:
>>>>>>>
>>>>>>> type nullTester func(*Bast, uint32) bool
>>>>>>>
>>>>>>> type Bast struct {
>>>>>>> ...
>>>>>>> isNull nullTester
>>>>>>> ...
>>>>>>> }
>>>>>>>
>>>>>>> func isNull(b *Bast, d uint32) bool {
>>>>>>> return d == 0
>>>>>>> }
>>>>>>>
>>>>>>> func NewBast() (b *Bast) {
>>>>>>> ...
>>>>>>> b.isNull = isNull
>>>>>>> ...
>>>>>>> }
>>>>>>>
>>>>>>> // IsNull - tests if a value in the tree is null
>>>>>>> func (b *Bast) IsNull(d uint32) bool {
>>>>>>> return b.isNull(b, d)
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>> Now, bear in mind I haven't shown all of the code. But there is a
>>>>>>> slice array in the Bast struct, and I it is defined as an interface{}
>>>>>>> and
>>>>>>> isNull is one of a set of operators that have to be written to match
>>>>>>> the
>>>>>>> type used in the slice store, this might be a bad example because it
>>>>>>> doesn't actually act on the interface typed slice, but the point here
>>>>>>> is
>>>>>>> just this:
>>>>>>>
>>>>>>> It does not appear to be possible to make the type specification
>>>>>>> from the top line match the function signature of the type-bound
>>>>>>> function
>>>>>>> in the bottom of the code snippet. I haven't been able to find anything
>>>>>>> that shows that a func type can have a method binding.
>>>>>>>
>>>>>>> https://github.com/calibrae-project/bast/blob/master/pkg/bast/bast.go
>>>>>>> is where my WiP lives. This slightly hacky solution seems sound to me,
>>>>>>> I
>>>>>>> just don't like to be forced to use workarounds like this. If a type
>>>>>>> signature cannot be written that matches a method, yet I can do it this
>>>>>>> way, I don't see what purpose this serves as far as any kind of
>>>>>>> correctness
>>>>>>> and bug-resistance issues go. I would have to deal with a lot more
>>>>>>> potential bugs if I had to concretely implemennt this library for the
>>>>>>> sake
>>>>>>> of 1 slice and 7 functions out of a much larger library that
>>>>>>> conceptually
>>>>>>> is intended to only deal with comparable, mainly numerical values
>>>>>>> anyway.
>>>>>>>
>>>>>>
--
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 [email protected].
For more options, visit https://groups.google.com/d/optout.