4

This might seem like a silly question, but I want to make a struct with a collection of functions, but the functions bind to the struct. I can sorta see that this is a cycle, but humor me with this example:

type FuncType func() error

type FuncSet struct {
  TokenVariable  int
  FuncTyper      FuncType
}

and I want to be able to create a function bound to the FuncSet type so it can operate on TokenVariable, thusly:

func (f *FuncSet) FuncType() error {
  f.TokenVariable = 100
  return nil
}

However, this changes the signature of the type (I can't find any information about type bindings as part of function type specifications) such that assigning this function to the struct element tells me this function/variable is not found.

I can see an easy work-around for this, by prefixing the parameters with a pointer to the struct type, it's just a bit ugly.

I looked around a little further and discovered that what I'm kinda looking for is like a closure in that it can be passed a variable from the immediate outer scope but... well, I'll be glad to be corrected about this absence of type binding in function types, but for now passing the pointer to the type looks like the way to go.

I think I found the solution:

type nullTester func(*Bast, uint32) bool

type Bast struct {
  ...
  isNull    nullTester
  ...
 }

func isNull(b *Bast, d uint32) bool {
  return d == 0
}

and then I can bind it to the type like this:

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

It seems a bit hackish and I'm not sure what's going to happen in a second library that I will write that sets a different type for the uint32 parameter, but go vet is happy so maybe this is the correct way to do it.

It does seem to me that func types should really have a field in the grammar to specify a binding type, but maybe I just found a hack that sorta lets me do polymorphism. In calling programs all they will see is the nice exported function that binds to the type as planned and I get my readability as well as being able to retarget the base library to store a different type of data.

I think this is the proper solution. I just can't find anything that confirms or denies whether in a type Name func specification there is any way of asserting the type. It really should not match up, since the binding is part of the signature, but the syntax for type with functions does not appear to have this type binding.

My actual code is here, and you can see by looking at it what I am aiming to do: https://github.com/calibrae-project/bast/blob/master/pkg/bast/bast.go

The differences between the type of data the tree stores is entirely superficial, because it is intended to be primarily used for sorting unsigned integers of various lengths, and one important thing it needs to have is to be able to work from a, for example, 64 bit integer but sort only by the first or last half (as I have a bigger project that treats these hash values as coordinates in an adjacency list). In theory it could be used instead of a hash table lookup as well, with a low variance in time to find elements because of the binary tree structure.

It's not a conventional, reference-vector based tree, and the store itself is an array with an unconventional power of two mapping, a 'dense' tree, and the purpose above all, for implementing this way, is that when the tree is walked, as well as rotated, much of the time it is sequential blocks of memory being accessed which should make for a lot less cache misses than a conventional binary tree (and for which reason generally this type of application just uses some kind of sort like a bucket sort).

6
  • Oh, I see that seemed to work. No, actually, it didn't: play.golang.org/p/xIbXg8ks2lO I mean, it worked as in, I was able to invoke these functions, and they assigned and all, but as soon as I removed the []FuncSet{} slice it can't find the functions, though I didn't change the name (and I can only assume it has to do with the signature including the type binding). Commented Apr 22, 2018 at 21:28
  • 3
    You might get more help if you try explaining the actual problem you're trying to solve instead of asking how to implement something that looks like a feature from another langauge. Commented Apr 22, 2018 at 21:33
  • Yes, it essentially implements function overrides. I'd be happy to learn a more idiomatic and less boiler-plate riddled route to the very simple goal: I have a tree library, and I want to be able to arbitrarily substitute any given data type in the payload of each node. The structure contains a slice array, and has a coordinate system and uses simple formulae based on the index to enable left/right/parent steps instead of using vector references. I ended up stumbling on this way to do it after I learned the 'type Name func()' thing. Commented Apr 22, 2018 at 21:45
  • 3
    I would love to help but you've given me two sentences and only one of those seems to have some significance to the problem you're trying to solve. As it stands now I'm unable to fully comprehend what you're trying to do and therefore unable to offer a solution. Maybe someone more knoledgable will join and help out, or, if you can, please update the original question with your actual question, include the relevant code: Tree, Node, how/where you need to do the arbitrary substitution, etc. Commented Apr 22, 2018 at 21:58
  • 1
    I don't quite understand what it is you want to do. From the playground code, it looks like you want to have a function you can call on a struct type and be able to change the behavior of that function. If that's the case, you could do that by defining a method on the type that calls Funct, which would still be a field that you could set to whatever function you want. That function would have to take a pointer to FuncSet as a parameter (instead of taking a receiver) so that the binding would be determined by the object you call Funct on. Commented Apr 22, 2018 at 22:00

1 Answer 1

2

You could use an anonymous field with an interface that defines the method set that you want to use (that might change).

Go playground here

You'd define your interface

type validator interface {
    IsRightOf(a, b interface{}) bool

    ... // other methods
}

and your type:

type Bast struct {
    validator // anonymous interface field

    ... // some fields
}

Then you can access the methods of validator from the Bast type

b := bast.New()
b.IsRightOf(c, d) // this is valid, you do not need to do b.validator.IsRightOf(...)

because validator is an interface you can change those methods how you like.

Sign up to request clarification or add additional context in comments.

1 Comment

That's an approach I hadn't seen before also. I am in the process of switching it all up so that my struct just stores a set of datatype agnostic function signatures with nice names, and a pointer to the same type, and then call them with b.Functionname(b, parameters...) Then I only use interfaces for the types, which pass through type agnostic functions into the type savvy (aka implementations). Saves on my previous overhead wrapping and stupid namespace. But maybe your idea is even better because I still can b.Functionname(<no pointer here> parameters...)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.