PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Wednesday, May 18, 2022

[FIXED] How do I achieve "C++-ish template specialization" in Swift with generics?

 May 18, 2022     c++, generics, partial, swift, templates     No comments   

Issue

I realize generics and templates are different, but I thought I'd throw out the C++-ish remark since someone familiar with templates would know what I am trying to accomplish. In the code below, I am trying to write one generic member method that handles strings in one overload variant. In the other variant, the method is supposed to handle numerical types that can be initialized from a string.

So, below, I want to take a map, and given a particular type of variable, look up the name in the map and parse it into the correct type. Unfortunately, I hit snags regarding the lack of an init() on the type(of:) and also a snag on the overload resolution where the Int type call wants to invoke the method that is defined for strings.

Here's the code:

protocol StringInitializable {
    init()
    init( _: String )
}

class Foo {
    var stringMember : String
    var intMember : Int

    var lookupMap : [String:String] = [
        "string" : "Your String",
        "int": "12"
    ]

    func extractType< ParseEntity: StringInitializable >( parameter: ParseEntity, lookupName: String ) throws -> ParseEntity? {
        var x : ParseEntity?
        x = type( of: ParseEntity ).init( lookupMap[ lookupName ] )
        return x
    }

    func extractType( parameter: String, lookupName: String ) throws -> String? {
        return lookupMap[ lookupName ]
    }

    init() {
        do {
            try extractType( parameter: stringMember, lookupName: "string" )
            try extractType( parameter: intMember, lookupName: "int")
        } catch {}
    }
}

The code is a bit hacky, but hopefully there is enough to convey the intention across. Any assistance at all is appreciated. Thanks in advance.


Solution

There were numerous problems with my formulation above, but I did eventually get what I wanted to work.

First, in StringInitializable, I needed the following:

protocol StringInitializable {
    init()
    init?(_ description: String)
}

Second, I had to extend Int and Float via a protocol extension to mark them as "String Initializable":

extension Double : StringInitializable {}
extension Int : StringInitializable {}

Third, type(of:) is not a pure replacement for something like __decltype() in C++. I needed to construct a "ParseEntity" in type(of:). So in my reformulated code, the critical line looked something like this:

    var x : ParseEntity? = type( of: ParseEntity() ).init( lookupMap[ lookupName ]! )

So final "working" example looks like this:

enum ParseError : Error {
    case BadParse( errorMessage: String)
}

protocol StringInitializable {
    init()
    init?(_ description: String)
}

extension Double : StringInitializable {}
extension Int : StringInitializable {}

class Foo {
    var stringMember : String = ""
    var intMember : Int = 0

    var lookupMap : [String:String] = [
        "string" : "Your String",
        "int": "12"
    ]

    func extractType< ParseEntity: StringInitializable >( parameter: ParseEntity, lookupName: String ) throws -> ParseEntity? {
        if let lookupEntry = lookupMap[ lookupName ] {
            return type( of: ParseEntity() ).init( lookupEntry )
        }
        throw ParseError.BadParse( errorMessage: "Bad parameter: \( lookupName )" )
    }

    func extractType( parameter: String, lookupName: String ) throws -> String? {
        if let lookupEntry = lookupMap[ lookupName ] {
            return lookupEntry
        }
        throw ParseError.BadParse( errorMessage: "Bad parameter: \( lookupName )" )
    }

    init() {
        do {
             stringMember = try extractType( parameter: stringMember, lookupName: "string" )!
             intMember = try extractType( parameter: intMember, lookupName: "int")!
        } catch ParseError.BadParse( let errorMessage ) {
            print( "\( errorMessage )" )
        } catch {}
    }
}


var f = Foo()
print( "\(f.intMember)" )
print( "\(f.stringMember)" )


Answered By - Parttime Voidray
Answer Checked By - Willingham (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing