Overloaded constructors in 2331 now fail to compile (Silver/Cooper)?

This valid swift used to compile as recently as .2321, but doesn’t in .2331, it gives a “Duplicate constructor” error. Which I’m guessing is fair enough in Java where you can’t overload constructors, but it used to work fine?

/// Used when an API can return String data or a fatal error.
open class DataOrError: NSObject
{
    
    fileprivate(set) open var error: String?
    fileprivate(set) open var data: String?
    
    public init(data: String)
    {
        self.data = data
    }
    
    public init(error: String)
    {
        self.error = error
    }
    
    open class func data(_ data: String) -> DataOrError
    {
        return DataOrError(data: data)
    }
    
    open class func error(_ error: String) -> DataOrError
    {
        return DataOrError(error: error)
    }
}

Similarly, all calls to DataOrError(error: ‘blah’) also fail to compile.

This is an unfortunate limitation of java itself. Constructors can’t be named there so they’ll match on their types. You can create a private init method that takes both error and data, and public convenience constructors that call those to get around this.

Thanks Carlo.
Interestingly the convenience inits suffered the same problem, but I will just change all the calling code to call the existing statics anyway:

Thanks, logged as bugs://81138

Yeah it’s a bit tricky. I thought convenience did a trick here but was confused. I’m going to see how to best solve this but for now your workaround will have to do.

Thanks, in this case there were only a dozen or so callers, so no big deal

Carlo, got more strangeness with constructors in 2331. This looks like a reasonably serious regression in 2331, and possibly related to the above.

The attached project is a small repro of a problem I’m having with constructors of Swift superclass and Java base class.

consoleapplication79999.zip (208.3 KB)

public typealias OpaquePointer = Int32
public class BasePtrWrapper
{
    
    internal var address: OpaquePointer

    
    public required init(ptr: OpaquePointer)
    {
        super.init()
        
        self.address = ptr
    }

}

@objc(AuthTokenWrapper)
open class AuthToken  : BasePtrWrapper
{
    /*
    public required init(ptr: OpaquePointer)
    {
        super.init(ptr: ptr)
    }
    */
}

let at = AuthToken(ptr: 333)
print(at)

Running it gives
!> Fatal exception of type java.lang.VerifyError on thread 0001 ()
!> Message: java.lang.VerifyError: (class: consoleapplication79999/__Global, method: main$ signature: ([Ljava/lang/String;)I) Call to wrong initialization method

If you uncomment out the overridden constructor, you get a similar error.
I can’t work out what’s actually the determining factor here.

In my actual project I end up with decompiled code that looks like this:

public class AuthToken extends BasePtrWrapper {
    public AuthToken(int ptr) {
        Object Result = null;
        super(ptr);
        return Result;
    }

Where returning a value from a constructor is the bytecode problem I guess.

Any workarounds appreciated, as its yet another blocker trying to upgrade to Fire 10, which I’ve been on for ~6 weeks now.

bugs://81138 got closed with status fixed.

Curious issue. For Island/Darwin we added Cocoa support and different class models. @Objc makes a class into those, and it confused the compiler. Fixed now.

Ah, thanks. The @objc is for the XCode cross compile. I’ll comment them out FTB so I can keep moving.

1 Like