How can I return an obj of a class parameter in a func in Echoes

I have a decode method, which decodes Json and returns a certain type of class thats passed in:

/// Service for parsing and serializing Json
public protocol JsonService
{
    /// Decodes a top-level value of the given type from the given JSON representation.
    ///
    /// - parameter type: The type of the value to decode.
    /// - parameter data: The data to decode from.
    /// - returns: A value of the requested type.
    /// - throws: `DecodingError.dataCorrupted` if values requested from the payload are corrupted, or if the given data is not valid JSON.
    /// - throws: An error if any value throws an error during decoding.
    #if os(iOS) || os(OSX)
    func decode<T>(_ type: T.Type, from bytes: Bytes) throws -> T where T : Decodable
    #endif
    #if NET
    func decode<T>(_ type: System.Type, from bytes: Bytes) throws -> T 
    #endif
    #if ANDROID
    func decode<T>(_ type: java.lang.Class<T>, from bytes: Bytes) throws -> T
    #endif

}

This is used like:

 let myObj: MyObject = jsonService.decode( MyObject.self, someJsonBytes)

As you can see I have to specialise the method signature for XCode, Cooper/Java & Echoes/.Net, as T.Type isnt valid in Silver.

This works well in XCode & Cooper/Java, but in Echoes/.Net I have problems because System.Type is not generic, like the other two.
The only way I can get this to work in Echose/.Net is to call like
jsonService.decode<MyObject>( MyObject.self, someJsonBytes)

Which would be ok, except that XCode hates this, and gives an error at this syntax:

So - looking for ideas or tricks how I can get the .Net/Echoes version working the same as the others, where the generic return type is specified by the type passed as the first param.
I guess worst case is I have to return Any, and force cast everywhere in client code. But ugly!

Best I can do that works across platform with one syntax is:

Cooper

class Decoder<T>
{
    var c: Class<T>
    init(_ type: Class<T>)
    {
        self.c = type
    }

    func decode() -> T
    {
        print(c)
        return c.newInstance() as! T
    }
}

class MyClass
{}

let my: MyClass = Decoder<MyClass>(MyClass.self).decode()
print(my)

Echoes

class Decoder<T>
{
    var c: System.Type
    init(_ type: System.Type)
    {
        self.c = type
    }

    func decode() -> T
    {
        print(c)
        return c.GetConstructors()[0].Invoke([]) as! T
    }
}

class MyClass
{}

let my: MyClass = Decoder<MyClass>(MyClass.self).decode()
print(my)

Which is ok I guess except for the verbosesness of the call: Decoder<MyClass>(MyClass.self).decode()

Thanks, logged as bugs://80965

This sounds like something we need to add proper support for.

As a workaround, if you use Elements for all platforms and use Elements RTL, there’s a cross-platform Type type you can use (similar to System.Type, except it is mapped properly on each platform, so you don’t need to ifdef).

you could add an inline function that passes the type via typeof:

class Decoder<T>
{
    var c: System.Type
    init(_ type: System.Type)
    {
        self.c = type
    }

    func decode() -> T
    {
        print(c)
        return c.GetConstructors()[0].Invoke([]) as! T
    }
  @inline(__always) static func decode() -> T
  {
    return Decoder<T>(T.self).decode()
  }
}
Decoder<MyClass>.decode()

Thanks Carlo, thats a cool technique of getting T that I didnt know about. Even works under Java type erasure!

You happy with that approach? If so I’ll close this task.

I’ll use that idiom for the time being, for sure.
I would be good if you could support T.Type in the long term though, as it’s standard swift, as in

func decode<T>(_ type: T.Type, from bytes: Bytes) throws -> T

My function is basically a polyfill of:
https://developer.apple.com/documentation/foundation/jsondecoder/2895189-decode

cheers

Jon