> > 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, matthe...@gmail.com 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, matthe...@gmail.com 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 golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.