Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/mobile: Java constructor proposal #17086

Closed
karalabe opened this issue Sep 13, 2016 · 7 comments

Comments

Projects
None yet
6 participants
@karalabe
Copy link
Contributor

commented Sep 13, 2016

I've been looking at the generated code for Android, and I think we could really make it a lot more natural by generating constructors for Java classes instead of relying on creator methods.

The idea behind my proposal is that we could simply detect specific function naming convention in Go, and if that holds, generate a constructor instead of a static method.

Basic constructors

If I were to have a type on Go side:

type SomeType struct {}

Then either of the functions below could be interpreted as a constructor for SomeType:

func NewSomeType(arg string) *SomeType {...}
func NewSomeType(arg string) (*SomeType, error) {...}

Instead of generating a static method in the root namespace, we could generate a public constructor:

class SomeType {
    public SomeType(String arg) { ... }
}

The rule would be that if a Go package contains both TypeXXX and a function NewTypeXXX which returns TypeXXX and optionally an error, we can interpret that as a constructor.

Overloaded constructors

An even more interesting (alas less obvious) case are overloaded constructors. Many times it can happen that we need to create a new "object" from multiple possibly input types.

One example of such is Go's binary package:

func NewBuffer(buf []byte) *Buffer { ... }
func NewBufferString(s string) *Buffer { ... }

In this case the "Basic" approach above would generate a constructor from the first, but not the second function. I'd propose that all functions called NewTypeXXX<whatever> that have the required signature (returns a pointer to a type and an optional error) is used to generate overloaded constructors.

Clashes

Of course, since we're "merging" different named methods under the same constructor name, there's nothing stopping me from defining multiple methods in Go that would en up with the same constructor signature.

func NewBuffer1(buf []byte) *Buffer { ... }
func NewBuffer2(buf []byte) *Buffer { ... }

In that case we can just fall back to the current behavior of retaining the methods and not creating constructors out of them.

I'd be happy to code this up if there's interest. @eliasnaur ? :)

@eliasnaur

This comment has been minimized.

Copy link
Contributor

commented Sep 13, 2016

This is precisely what I have implemented as part of my proposal at #16876. I implemented automatic constructors for different reasons than you:

  1. My proposal enables Go structs to extend and implement Java classes and interfaces. I needed to implement automatic constructors to access the arguments to non-empty super class constructors. This point is irrelevant to this proposal.
  2. Instance identity: If you new Something(...) from Java, you expect that instance to stay constant. In Gomobile that is not true today: If you pass in a Java Something instance to Go, it is unwrapped to a Go Something instance. If that Go instance is then passed to Java again, either as an argument or return value, it is re-wrapped in a different Java Something instance. For my proposal I needed instance identity and I needed to retain the state from Java super classes (consider an Android Activity implemented in Go. Re-wrapping that instance won't work).

The instance identity only covers Go structs extending or implementing Java classes and interfaces. Generalizing instance identity to cover every Go (and Java) type doesn't (readily) work: Gomobile statically determines the proxy type from the call site, not the actual type of the argument or return value. So if you have a Go struct S, it might appear as an Java S at one calls, while being a Java I in another. In that case, maintaining instance identity for the two sites is impossible since Java S and I are different types.

Preserving instance identity is attractive for several other reasons (fewer proxy allocations and the property that for equal Go instances, the proxies are also equal), so I haven't given up yet. However, I believe automatic constructors are not meaningful without some form of identity preservation.

@quentinmit quentinmit added this to the Unreleased milestone Sep 13, 2016

@gedw99

This comment has been minimized.

Copy link

commented Sep 22, 2016

I hot this exact problem today.

Creative g the constructors would be nice I feel

@eliasnaur

This comment has been minimized.

Copy link
Contributor

commented Sep 22, 2016

#16876 is now in, and you should be able to create a cosntructor for a Go struct simply by embedding a Java class. For example

import "Java/java/lang"

type S struct {
   lang.Object
}

will make new S() available to Java. I'm still against doing this for every Go struct, because of the instance identity issues I described in my previous message.

@karalabe

This comment has been minimized.

Copy link
Contributor Author

commented Sep 22, 2016

Though this would break building the same code for both android and ios. Perhaps by using build constraints?

@eliasnaur

This comment has been minimized.

Copy link
Contributor

commented Sep 23, 2016

Ok, let's try it. I've mailed CL 29710 to expand support for generating constructors to every exported Go struct.

@gopherbot

This comment has been minimized.

Copy link

commented Sep 23, 2016

CL https://golang.org/cl/29710 mentions this issue.

@adg

This comment has been minimized.

Copy link
Contributor

commented Sep 26, 2016

@golang golang locked and limited conversation to collaborators Oct 5, 2017

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.