Just want to know if it will ever be possible to support slices of supported. I currently have to write a wrapper object around an array to pass it back and forth between IOS and Go.

Comment From: bradfitz

/cc @crawshaw @hyangah

Comment From: hyangah

It will not be impossible and eventually it should be supported. I don't know anyone who's currently working on this problem.

Comment From: dcu

yeah this is the most frustrating issue for me right now

Comment From: weitzj

Do you have any ideas when this will be done? What I could do?

I tried and failed using: https://golang.org/pkg/container/list/ as an alternative

Comment From: ioArchman

+1 Would highly recommend this as currently falling short without this.

Comment From: mpiannucci

This is stopping me from using gomobile in anything worthwhile at the moment

Comment From: ioArchman

@scisci - If you don't mind can you please share across a gist on how you handle the problem currently as said? My requirement would be to return an array/slice of custom modal class objects with 4 string properties.

Comment From: scisci

hi @ioArchman, I made a quick repo here:

https://github.com/scisci/go-mobile-collection

If you think it can work for you, you will probably want to fork it and modify the render.go function to add/remove the methods you want on your collection wrapper. Feel free to make a comment on the project if you have any questions. Its pretty directly adapted from another tutorial on go generics, which you can find here http://www.onebigfluke.com/2014/12/generic-programming-go-generate.html

Keep in mind, I don't consider this a good solution. It feels hacky working with a wrapper on the objective-c/swift side, but it does work. Really would prefer something that feels more natural.

Comment From: ioArchman

Thanks @scisci. Will look into this and try utilizing for now. Agreed on your last point too.

Comment From: scisci

hi @hyangah, do you have any hints on how this would be technically implemented in case someone wanted to attempt it from outside the gomobile team?

Comment From: anacrolix

👍

Comment From: anacrolix

This is very limiting.

Comment From: kmcrawford

Is this still on the road map? I found this library and would like to use it, but this issue may be keep me from using gomobile.

Comment From: kliron

It seems this is a show-stopper for many people. Are there any plans to support this?

Comment From: 4h0q

What's the status of this issue? It has been around for quite a while. It looks like the main show stopper for many people.

CC: @hyangah @crawshaw

Comment From: dradtke

I just ran into this, and it would be great to be able to support slices.

Comment From: saurabha5

Just linking the stack overflow question here : https://stackoverflow.com/questions/44382115/golang-gomobile-tool-for-cross-platform-slices-of-struct-return-type

Comment From: nhatlee

have any update for this issue?

Comment From: gituser9

Will there be any news?

Comment From: hyangah

Currently no one is working on the x/mobile project and adding this feature is not a small project.

Not ideal but need to work around by writing a wrapper package for binding, or using what @scisci mentioned for now.

Comment From: gituser9

Does the project have a future?

Comment From: bradfitz

It's community supported at this point, so its future depends on you. There are others from the community working on it, but not full time.

Comment From: MariusVanDerWijden

Anyone currently working on this? If not, could you give some pointers where to start with this?

Comment From: makivlach

As a really slow and dumb bypass, you could serialize the data into JSON, pass the string and unserialize it on the other side. Use this only as a last resort, though.

Comment From: vladimir-skorokhodov

A workaround from my real project. Maybe will helpful for someone. On Go side:

type Field struct {
    Key       string
    Value     string
    Protected bool
}

type FieldReceiver interface {
    Add(field *Field)
}

func GetEntryFields(receiver FieldReceiver) {
    for _, v := range entry.Values {
        field := Field{
            Key:       v.Key,
            Value:     v.Value.Content,
            Protected: v.Value.Protected}
        receiver.Add(&field)
    }
}

Android side:

val fields = mutableListOf<Field>()
Mylib.getEntryFields() { field ->
    run {
        fields += Field(field.key, field.value, field.protected)
    }
}

Comment From: nrobi144

A workaround with String as an example:

type StringCollection interface {
    Add(s string) StringCollection
    Get(i int) string
    Size() int
}

// TODO solve this with generics
type StringArray struct {
    items []string
}

func (array StringArray) Add(s string) StringArray {
    array.items = append(array.items, s)
    return array
}

func (array StringArray) Get(i int) string {
    return array.items[i]
}

func (array StringArray) Size() int {
    return len(array.items)
}

Usage in go:

func GetExampleStringArray() *StringArray {
    strings := []string{"example1", "example2"}
    return &StringArray{items: strings}
}

On Android you can use this extension to convert it to a List<String>:

fun StringArray.toStringList(): List<String> {
    val list = mutableListOf<String>()
    for (i in 0 until size()) {
        list.add(get(i))
    }
    return list
}

fun main() {
    GoPackage.getExampleStringArray().toStringList()
}

Comment From: tex0l

Is there any news? I was very surprised that this isn't implemented by default, I need to make very ugly workarounds to make my binding work.

Comment From: coder-free

Is there any news?

Comment From: kevmo314

I've implemented most of the work required for slices of structs here: https://github.com/golang/mobile/pull/101

I could certainly use some help on the final stretch though, especially if you've managed to get the gobind test environment working correctly. In particular, I think the last bits necessary are to: 1. Update the go-side refnum marshalling 2. Add an Obj-C implementation 3. Test that it all works

Comment From: gopherbot

Change https://go.dev/cl/583196 mentions this issue: bind: support slices of structs

Comment From: ezoushen

@kevmo314 Hi, I’m willing to help finish the work on the Objective-C side. Could you provide me with some guidance on how to collaborate?

Comment From: dockerdavid

@makivlach thank you, i fixed my code in gomobile

Comment From: JackieLeee

I also encountered this issue, and due to this problem, I might not be able to use gomobile to achieve the functionality I want.

Comment From: Edw590

I'm not sure this is helpful for this thread as I think it's solely about structs, but maybe gives a light to someone?

Just as an idea, if it's an array of strings, one could put it all in the same string and separate each by a special character, like "|". Or a non-printable one, like the null character.

If it's numbers that's worse - but can still be done. With a byte array. You convert the numbers to bytes and you know each number has for example 4 bytes. Then you can divide them back to ints in whatever language you're using Go with. And to separate, you could use a combination of bytes that won't be a number for sure (for example 5 random bytes - if the numbers are 4 bytes, you'd use 5 bytes to separate).

Also works for random bytes. I separated a stream of bytes (output of a shell command: the exit code, stdout and stderr all sent in the same byte array out of Go to Java) by a random big array of bytes (50 random bytes I think?). Then in Java I just got the first 4 bytes and converted to int and separated the rest with the byte array and the first was the stdout and the 2nd the stderr.


Specifically for structs, an idea is to have a function add a new struct to a Go-internal array. So you'd have a function with as many parameters as the struct and that function adds to a Go array. Each struct must have an ID (or use its index). Then there's a getter for the struct by its ID. That's how I'm doing with an array of structs.

Maybe this can help someone (?).

Comment From: ezoushen

@Edw590 This approach feels somewhat like what protobuf does, doesn’t it? 🤔 But still interesting though.

Comment From: fingon

FWIW we're just using gomobile to start GRPC server, and then generate stubs for Swift side to talk with Go code using GRPC. This solved so many issues it is not even funny (e.g. gomobile default of 'if field is not supported, we ignore it' bit us in the ass so many times.. same also with some name mangling issues).

We get all datatsructures protobuf supports too ;-)

Comment From: ezoushen

@fingon Cool solution! Have you tested the overhead (both CPU and RAM) of running an additional gRPC server compared to using pure Gomobile?

Comment From: fingon

@fingon Cool solution! Have you tested the overhead (both CPU and RAM) of running an additional gRPC server compared to using pure Gomobile?

It is quite performant. We have also backup plan of defining GRPC channel which just calls the gomobile'd function (instead of using TCP+HTTP/2) with arbitrary byte arrays to avoid networking, but so far it has not been necessary.

We have heavy Go backend + lightweight Swift (and eventually Android) UI.

Comment From: gabemeola

Something that worked for me was turning slices into an Pull Iterator pattern. I'm using nil pointers to signal done but you could expose this as another method.

type Iterator[T any] struct {
    data  []T
    index int
}

func (s *Iterator[T]) Next() *T {
    if s.index >= len(s.data) {
        return nil
    }

    data := &s.data[s.index]
    s.index++
    return data
}

Although I couldn't get gomobile / gobind to with with Struct generics so I needed a concrete type

type DataIterator struct {
    data  []Data
    index int
}

func (s *DataIterator) Next() *Data {
    if s.index >= len(s.data) {
        return nil
    }

    data := &s.data[s.index]
    s.index++
    return data
}

Usage in Swift

while let data = iter.next() {
  ...
}