Is the need for a memory efficient implementation backed by a performance 
profile?

Matt

On Monday, April 23, 2018 at 10:26:41 AM UTC-5, Louki Sumirniy wrote:
>
> First issue is that BAST does not use references. This is so that searches 
> proceed linearly through memory. Instead it uses a flat array that it cuts 
> into sequentially doubling sized rows, representing the slots that a binary 
> tree has.
>
> Secondly, you just complicated my design even further with 'is left 
> equal'. why not just 'go left' 'is this equal'?
>
> The implementation of the comparison could be different for all kinds of 
> reasons. Number one reason that is already on my plan of action is where I 
> have an arbitrary bit-width data, say 64 bits, but I want to sort one tree 
> by the first 32 bits, and the same data feed into another tree at the same 
> time that searches/sorts by the second 32 bits. This is the main reason for 
> needing this flexibility. Mainly I want to stick to small blobs of memory, 
> just numbers, mostly, but that at least includes 256 bit values. Much 
> beyond that will destroy the advantage of this scheme, in that the tree 
> will be too big in memory because of how large the probably 1/4 to 
> half-filled node collection will generally be.
>
> On Monday, 23 April 2018 17:28:09 UTC+3, matthe...@gmail.com wrote:
>>
>> 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.

Reply via email to