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)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.