Swift BinaryFloatingPoint generic exposes compile error on log10() invocation - swift

What protocol should T complies with to pass this error?
class func magnitude<T: BinaryFloatingPoint>(_ n: T) where T: CVarArg {
// …
let p = Int(log10(n))
// …
}
The error is as follows:
Cannot invoke 'log10' with an argument list of type '(T)'

Based on Martin R tips, I came up with the following (I added fictional code so that one can compile it), which works nice:
protocol FloatingPointMathType : BinaryFloatingPoint, CVarArg {
var _log10Value : Self { get }
}
extension Float: FloatingPointMathType {
var _log10Value : Float {return log10(self)}
}
extension Double: FloatingPointMathType {
var _log10Value : Double {return log10(self)}
}
extension CGFloat: FloatingPointMathType {
var _log10Value : CGFloat {return log10(self)}
}
func log10<T:FloatingPointMathType>(_ x:T) -> T {return x._log10Value}
class Format {
class func magnitude<T: BinaryFloatingPoint>(_ n: T) -> Int {
let p = Int(log10(n))
return p
}
}
let d: Double = 12.0
print(Format.magnitude(d))

Related

Can a base class extension capture and return specific implementation?

Suppose we have:
class BaseClass {
var id: String
}
class Child1: BaseClass {}
class Child2: BaseClass {}
struct Structure<T : BaseClass> {
var map = [String: T]()
}
Is it possible for an extension to return the specific type?
extension BaseClass {
static func <- <T : BaseClass>(left: T, right: T) -> Structure<T> where T == Self {
return Structure(map: [left.id, right])
}
}
The compiler doesn't like T == Self, or the left/right operator being T, but you can see what I'm trying to do. I'm trying to return the specific type of BaseClass so that I only have to implement these operators once.
So then you could use it like this:
var child1 = Child1()
var child11 = Child1()
// the structure returned matches the type of the operator inputs
var structure: Structure<Child1> = child1 + child11
If I try to put T in the operator left, right params, the compiler doesn't like that either.
This also doesn't work (for obvious reasons), but if there a way I could rewrite it to make it work?
extension BaseClass {
func combine<T : BaseClass>(with: T) -> Structure<T> {
// this doesn't work because 'self' can be assumed to be T
return Structure<T>(map: [self.id : with])
}
}
You can define the operator. You just can't put it inside of a type.
func + <T>(left: T, right: T) -> Structure<T> {
.init(map: [left.id: right])
}
var structure = Child1() + Child1()
If you want it to be a method, you'll need a protocol.
protocol BaseClassProtocol: BaseClass { }
extension BaseClassProtocol {
func combine(with instance: Self) -> Structure<Self> {
.init(map: [id: instance])
}
}
extension BaseClass: BaseClassProtocol { }
…but if you're going to have a protocol, you can throw the operator in there too if you want.
extension BaseClassProtocol {
static func + (left: Self, right: Self) -> Structure<Self> {
.init(map: [left.id: right])
}
func combine(with instance: Self) -> Structure<Self> {
self + instance
}
}

Protocol Having generic function and associatedType

I've the following code:
protocol NextType {
associatedtype Value
associatedtype NextResult
var value: Value? { get }
func next<U>(param: U) -> NextResult
}
struct Something<Value>: NextType {
var value: Value?
func next<U>(param: U) -> Something<Value> {
return Something()
}
}
Now, the problem is in the Something implementation of next. I want to return Something<U> instead of Something<Value>.
But when I do that I got the following error.
type 'Something<Value>' does not conform to protocol 'NextType'
protocol requires nested type 'Value'
I tested the following codes and they compile (Xcode 7.3 - Swift 2.2). In this state they are not very useful, but I hope it helps you to find the final version you need.
Version 1
Since, Something is defined using V, I think you can't return just Something<U>. But you can redefine Something using U and V like this:
protocol NextType {
associatedtype Value
associatedtype NextResult
var value: Value? { get }
func next<U>(param: U) -> NextResult
}
struct Something<V, U>: NextType {
typealias Value = V
typealias NextResult = Something<V, U>
var value: Value?
func next<U>(param: U) -> NextResult {
return NextResult()
}
}
let x = Something<Int, String>()
let y = x.value
let z = x.next("next")
Version 2
Or just define Something using V:
protocol NextType {
associatedtype Value
associatedtype NextResult
var value: Value? { get }
func next<U>(param: U) -> NextResult
}
struct Something<V>: NextType {
typealias Value = V
typealias NextResult = Something<V>
var value: Value?
func next<V>(param: V) -> NextResult {
return NextResult()
}
}
let x = Something<String>()
let y = x.value
let z = x.next("next")

Can I specify that a class instance can be converted to some type?

Say I have a generic class
class Foo<T> { … }
Can I somehow specify that instances of this class can be converted to T in assignments? Example:
let foo = Foo<Int>()
func useAnInt(a: Int) {}
let getTheInt: Int = foo
useAnInt(foo)
Why not just use the underlying type? (Similar to #MrBeardsley's answer)
class Foo<T> {
var t : T
init(t: T) {
self.t = t
}
}
let foo = Foo(t: 3)
func useAnInt(a: Int) {}
let getTheInt: Int = foo.t
useAnInt(foo.t)
You are not able to do what you are asking. Even though Foo defines a generic type T, instances of Foo are still Foo and cannot be converted to the generic type. The reason you would declare a generic type at the class level is to use it multiple places throughout the class.
class Foo<T> {
var value: T
init(withValue: T) {
self.value = withValue
}
func getSomeValue() -> T {
return self.value
}
}
Generics don't mean the class itself is generic and can be converted.
One way of achieving what you want is to use a dedicated protocol for each of the target types that your class shall be convertible to. Here is very basic example:
protocol BoolAdaptable {
func adaptToBool() -> Bool
}
protocol IntAdaptable {
func adaptToInt() -> Int
}
protocol FloatAdaptable {
func adaptToFloat() -> Float
}
class Foo: BoolAdaptable, IntAdaptable, FloatAdaptable {
var v: NSNumber
init(_ v: NSNumber) {
self.v = v
}
func adaptToBool() -> Bool {
return v.boolValue
}
func adaptToInt() -> Int {
return v.integerValue
}
func adaptToFloat() -> Float {
return v.floatValue
}
}
let foo = Foo(NSNumber(double: 1.23))
let getTheBool = foo.adaptToBool() // true
let getTheInt = foo.adaptToInt() // 1
let getTheFloat = foo.adaptToFloat() // 1.23
This could easily be extended to support more complex conversions.

How to create a function that returns a generic protocol type?

In the following code, I have a generic protocol Var and it have a private implementation class LambdaVar. Now I want to have a function that return an instance of the LambdaVar without expose it publicly.
But I can't find a way to define a function that return a generic protocol type.
public protocol Var {
typealias ValueType
var value : ValueType { get }
}
struct LambdaVar<T> : Var {
let _get : Void -> T
init(_ f : Void -> T)
{
_get = f
}
var value : T {
get {
return _get()
}
}
}
public func transform<T : Var, U>(v : T, f : T.ValueType -> U) -> Var<U> {
return LambdaVar<U>() { f(v.value) } // ^^^^^^ what to put here?
}
Error:
Playground execution failed: <EXPR>:26:67: error: cannot specialize non-generic type 'Var'
public func transform<T : Var, U>(v : T, f : T.ValueType -> U) -> Var<U> {
^
<EXPR>:26:67: error: protocol 'Var' can only be used as a generic constraint because it has Self or associated type requirements
public func transform<T : Var, U>(v : T, f : T.ValueType -> U) -> Var<U> {
You should create simple wrapper type of Var like SequenceOf<T>:
struct VarOf<T>:Var {
let f:Void->T
init<V:Var where V.ValueType == T>(_ v:V) {
f = { v.value }
}
var value:T {
return f()
}
}
func transform<T : Var, U>(v : T, f : T.ValueType -> U) -> VarOf<U> {
return VarOf(LambdaVar<U>({ f(v.value) }))
}
let intVar = VarOf(LambdaVar({ 12 }))
let floatVar = transform(intVar, { Float($0) })
floatVar.value // -> 12.0

How to make a mutating function in an extension return Int using Swift?

Why doesn't this code work?
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
var x:Int = 7
let y:Int = x.adjust()
here is what I get on XCODE
is there a way to make adjust() return Int without changing its definition in the protocol?
Yes, you can give adjust a return value. Define it to return an Int in the protocol and class, then have it return itself in the mutating method:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust() -> Int
}
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() -> Int {
self += 42
return self
}
}
var x:Int = 7
let y:Int = x.adjust() //49
Because the adjust() function does not return value (it just change the value of its instance), you can achieve this by this orders:
var x:Int = 7
x.adjust() //adjust x self value
let y:Int = x //assigne x value to y
Hope this helps.
Ques : is there a way to make adjust() return Int without changing its definition in the protocol?
Ans : No
The definition/signature of a method tells us what it's going to take as input and what data type it's going to return.
You need to return an Int from a method then it's signature should end with -> Int. That's the syntax ! Can't change it.
connor has provided the right piece of code you need.