ambiguous use of init with default values - swift

I have class that have two similar looking initializers:
public init(
contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
midToLeftSpacing: CGFloat = 0,
rightToMidSpacing: CGFloat = 0
)
public init(
contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
midToLeftSpacing: MyInsetLevel = .level0,
rightToMidSpacing: MyInsetLevel = .level0
)
Now i run into problem, looks like when i trying to call initializer compiler can't figure out which one to chose:
init(
vertical: .level0,
left: .level22,
right: .level0
)
Gives error - Ambiguous use of 'init'
It could be easily fixed with modifying initializer or adding next argument with default value, but it doesn't look right, is there any other way to specify init method called?

Your example doesn't match your code (there is no init(vertical:left:right) defined), so I'm going to try to generalize this problem a bit with a full example that avoids the extra types. I'll just use Double and Int here.
Imagine a struct X that internally stores three Doubles:
struct X {
var x: Double
var y: Double
var z: Double
init(x: Double = 0, y: Double = 0, z: Double = 0) {
self.x = x
self.y = y
self.z = z
}
}
You also want to be able to pass three Ints instead, but all three must either be Doubles or Ints, and you want default values. Every use of default values is just a shorthand for an extra method with fewer parameters. To avoid conflicts, you need to include at least one of the parameters as non-default:
extension X {
init(x: Int, y: Int = 0, z: Int = 0) {
self.init(x: Double(x), y: Double(y), z: Double(z))
}
init(y: Int, z: Int = 0) { self.init(x: 0, y: y, z: z) }
init(z: Int) { self.init(x: 0, y: 0, z: z) }
}
Now, every combination is legal, but there are no ambiguities.
This is nice when there's just one extra way to call the init. But maybe you want there to be many. Then a protocol is useful. For example, this approach allows either Int or Double for every parameter:
protocol XParameter {
var xParameterValue: Double { get }
}
extension Double: XParameter {
var xParameterValue: Double { self }
}
extension Int: XParameter {
var xParameterValue: Double { Double(self) }
}
struct X {
var x: Double
var y: Double
var z: Double
init(x: some XParameter = 0, y: some XParameter = 0, z: some XParameter = 0) {
self.x = x.xParameterValue
self.y = y.xParameterValue
self.z = z.xParameterValue
}
}

Related

Calling variadic C function from Swift with pointers

I'm trying to figure out how to call variadic C functions that write to pointers from Swift, such as vsscanf, but I don't understand how to actually construct the list of pointers to Swift variables.
I figure that if I have a string, I can get an UnsafePointer<CChar> and call vsscanf on it, but... how do I tell it where to actually write the data? How do I construct the CVaListPointer to pass to vsscanf?
var a: Int
var b: Float
"(5, 3.14)".withCString{buffer in
let r = vsscanf(buffer, "(%d, %f)", /* how do I put a and b here? */)
}
Basically, doing the same thing as here (C):
#include <stdio.h>
#include <stdarg.h>
int parse(const char *buffer, char *format, ...)
{
va_list args;
va_start(args, format);
int result = vsscanf(buffer, format, args);
va_end(args);
return result;
}
int main(int argc, char const *argv[])
{
int a;
float b;
char s[] = "(5, 3.14)";
int r = parse(s, "(%d, %f)", &a, &b);
printf("a: %d, b: %f\n", a, b);
// "a: 5, b: 3.140000"
return 0;
}
UPDATE: Thanks to the answers so far, I feel like I understand how this works a bit better, but what I'm still struggling with is populating the CVaListPointer in an easier way. Here's an example of parsing a triplet of Doubles out of a string:
func parseVec3(s: String) -> (Double, Double, Double)? {
var x: Double = 0
var y: Double = 0
var z: Double = 0
let r = s.withCString { buffer in
withUnsafeMutablePointer(to: &x) { ptrx in
withUnsafeMutablePointer(to: &y) { ptry in
withUnsafeMutablePointer(to: &z) { ptrz in
withVaList([ptrx, ptry, ptrz]) { va in
return vsscanf(buffer, "(%lf %lf %lf)", va)
}
}
}
}
}
return r == 3 ? (x, y, z) : nil
}
if let v = parseVec3(s: "(1 2 3)") {
print(v)
}
Now, this does work. But my problem is that I'm parsing a file where the bulk of the lines (thousands upon thousands of them) are six groups of triplets of numbers. The towering structure of withUnsafeMutablePointer would look downright ridiculous. I'm sure I could parse it using some more Swift-native approach (or just regex) but I was hoping to just use vsscanf because parsing this file in C is outrageously simple:
int main(int argc, char const *argv[])
{
char s[] = "(1 2 3) (5 9 1) (0 5 8)";
Vec3 a, b, c = {0, 0, 0};
sscanf(s,
"(%f %f %f) (%f %f %f) (%f %f %f)",
&(a.x), &(a.y), &(a.z),
&(b.x), &(b.y), &(b.z),
&(c.x), &(c.y), &(c.z)
);
printf("a: (x: %f, y: %f, z: %f)\n", a.x, a.y, a.z);
printf("b: (x: %f, y: %f, z: %f)\n", b.x, b.y, b.z);
printf("c: (x: %f, y: %f, z: %f)\n", c.x, c.y, c.z);
return 0;
}
Doing this with the withUnsafeMutablePointer approach in Swift as above would result in 11 with<Whatever> scopes, and that's only half of the floats parsed...
I figure I should be able to do something like this, but I can't figure out how to get the pointer offset to the other struct members:
func parseVec3_3(s: String) -> Vector3? {
var output = Vector3(x: 0, y: 0, z: 0)
var r: CInt = 0
s.withCString { buffer in
withUnsafeMutablePointer(to: &output) { ptr in
withVaList([ptr, /* offset pointer here */]) { va in
r = vsscanf(buffer, "(%lf %lf %lf)", va)
}
}
}
return r == 3 ? output : nil
}
Like this:
var a: Int = 0
var b: Float = 0
withUnsafePointer(to: &a) { pointerToA in
withUnsafePointer(to: &b) { pointerToB in
withVaList([pointerToA, pointerToB]) { va_list in
"(5, 3.14)".withCString { buffer in
let r = vsscanf(buffer, "(%d, %f)", va_list)
}
}
}
}
print(a)
print(b)
outputs
5
3.14
Update
The answer for OP edit including question about Vector3(x: 0, y: 0, z: 0) should become:
public struct Vector3: Equatable {
public var x: CGFloat
public var y: CGFloat
public var z: CGFloat
public init(x: CGFloat, y: CGFloat, z: CGFloat) {
self.x = x
self.y = y
self.z = z
}
}
func parseVec3_3(s: String) -> Vector3? {
var output = Vector3(x: 0, y: 0, z: 0)
var r: CInt = 0
s.withCString { buffer in
withUnsafePointer(to: &output) { (outputPointer: UnsafePointer<Vector3>) in
outputPointer.withMemoryRebound(to: CGFloat.self, capacity: 3) {
withVaList([OpaquePointer($0), OpaquePointer($0.advanced(by: 1)), OpaquePointer($0.advanced(by: 2))]) { va in
r = vsscanf(buffer, "(%lf %lf %lf)", va)
}
}
}
}
return r == 3 ? output : nil
}
if let vector: Vector3 = parseVec3_3(s: "(1.0 2.0 3.0)") {
print(vector)
}
outputs
Vector3(x: 1.0, y: 2.0, z: 3.0)
From the documentation on CVarArgs:
To create a wrapper for the c_api function, write a function that takes CVarArg arguments, and then call the imported C function using the withVaList(_:_:) function.
Swift only imports C variadic functions that use a va_list for their arguments. C functions that use the ... syntax for variadic arguments are not imported, and therefore can’t be called using CVarArg arguments.
Your wrapper function could look like:
func vsscanfSwiftWrapper(
buffer: UnsafePointer<CChar>,
format: UnsafePointer<CChar>,
_ arguments: CVarArg...
) -> CInt {
withVaList(arguments) { vaList in
vsscanf(buffer, format, vaList)
}
}

loading series of struct from data in Swift [duplicate]

This question already has answers here:
round trip Swift number types to/from Data
(3 answers)
Swift 5.0: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(...)
(4 answers)
Closed 1 year ago.
I am not sure where I got this piece of code. But here I have some code to get series of Vertex(or whatever) out of Data in swift.
struct Vertex {
var x, y, z, w: Float16
var r, g, b, a: Float16
}
extension Data {
func elements<T>() -> [T] {
return withUnsafeBytes {
Array(UnsafeBufferPointer<T>(start: $0, count: count/MemoryLayout<T>.stride))
}
}
}
It works fine to me, but I have this warning. I spent some time, but I cannot figure this out. So could someone please help me out?
'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead
By the way, I am trying to save and load large number of data with this way with pairing of following piece of code.
extension Array {
var data: Data {
var value = self
return NSData(bytes: &value, length: MemoryLayout<Element>.stride * self.count) as Data
}
}
Thank you,
EDIT
Here is the code what I like to do, it works fine, but I like to get rid of warning...
struct Vertex: Equatable {
var x, y, z, w: Float16
var r, g, b, a: Float16
// assumption: no precision error
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w &&
lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && lhs.a == rhs.a
}
}
let v0 = Vertex(x: 1, y: 2, z: 3, w: 4, r: 0, g: 0.25, b: 0.5, a: 0.75)
let v1 = Vertex(x: 5, y: 6, z: 7, w: 8, r: 0.2, g: 0.4, b: 0.6, a: 0.8)
let v2 = Vertex(x: 9, y: 0, z: 1, w: 2, r: 0.5, g: 0.75, b: 0.0, a: 1.0)
let original: [Vertex] = [v0, v1, v2]
let data = original.data
print(data as NSData)
let restored: [Vertex] = data.elements()
let w0 = restored[0]
let w1 = restored[1]
let w2 = restored[2]
print(v0 == w0)
print(v1 == w1)
print(v2 == w2)
First make your struct conform to ContiguousBytes:
extension Vertex: ContiguousBytes {
func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
try Swift.withUnsafeBytes(of: self) { try body($0) }
}
}
Then create a custom initializer on ContiguousBytes to allow initializing any type that conforms to it with contiguous bytes:
extension ContiguousBytes {
init<T: ContiguousBytes>(_ bytes: T) {
self = bytes.withUnsafeBytes { $0.load(as: Self.self) }
}
}
To extract the bytes/data from the types that conform to it:
extension ContiguousBytes {
var bytes: [UInt8] { withUnsafeBytes { .init($0) } }
var data: Data { withUnsafeBytes { .init($0) } }
}
Now you can simply make the magic happen.
Playground testing:
struct Vertex {
var x, y, z, w: Float16
var r, g, b, a: Float16
}
let vertex = Vertex(x: 1.2, y: 2.3, z: 3.4, w: 4.5, r: 0.5, g: 0.6, b: 0.7, a: 1)
let bytes = vertex.bytes // [205, 60, 154, 64, 205, 66, 128, 68, 0, 56, 205, 56, 154, 57, 0, 60]
let loadedVertex = Vertex(bytes)
print(loadedVertex) // Vertex(x: 1.2, y: 2.3, z: 3.4, w: 4.5, r: 0.5, g: 0.6, b: 0.7, a: 1.0)
edit/update:
to convert your bytes to a collection of vertices:
extension Array {
var data: Data {
var value = self
return .init(bytes: &value, count: MemoryLayout<Element>.stride * count)
}
}
extension ContiguousBytes {
func objects<T>() -> [T] { withUnsafeBytes { .init($0.bindMemory(to: T.self)) } }
var vertices: [Vertex] { objects() }
}
let vertex1 = Vertex(x: 1.2, y: 2.3, z: 3.4, w: 4.5, r: 0.5, g: 0.6, b: 0.7, a: 1)
let vertex2 = Vertex(x: 2.3, y: 3.4, z: 4.5, w: 5.6, r: 1, g: 0.8, b: 1, a: 1)
let data = [vertex1, vertex2].data
let loadedVertices = data.vertices
print(loadedVertices) // [__lldb_expr_8.Vertex(x: 1.2, y: 2.3, z: 3.4, w: 4.5, r: 0.5, g: 0.6, b: 0.7, a: 1.0), __lldb_expr_8.Vertex(x: 2.3, y: 3.4, z: 4.5, w: 5.6, r: 1.0, g: 0.8, b: 1.0, a: 1.0)]
To mirror what is being done in .data I believe you just want to copy the bytes directly into the Array. This is all pretty dangerous, because it's making some pretty strong assumptions around memory management (if T, or any property of T were a class or included hidden classes internally, the reference counts could be wrong). So I'd be really uncomfortable making this a generic extension like this. But for Float16 it's probably fine, assuming that you never encounter an endian issue (or an architecture that pads differently).
But to just do what you're doing, I'd recommend:
extension Data {
func elements<T>() -> [T] {
Array(unsafeUninitializedCapacity: count/MemoryLayout<T>.stride) { buffer, initializedCount in
copyBytes(to: buffer)
initializedCount = buffer.count
}
}
}

Getting the initialiser values in Swift 3

Essentially I am creating a new data type called Vector3.
class Vector3 {
var x:Int
var y:Int
var z:Int
init(x:Int,y:Int,z:Int) {
self.x = x
self.y = y
self.z = z
}
}
I used the operator overloading feature in Swift in order to use operators on my custom data types.
infix operator +
func +(left:Vector3,right:Vector3) -> Vector3 {
return (Vector3(x: left.x + right.x, y: left.y + right.y, z: left.z + right.z))
}
var customVector = Vector3(x: 1, y: 2, z: 3)
var secondVector = Vector3(x: 3, y: 2, z: 1)
print(customVector + secondVector) //Take note
Currently the console is printing like this:
Vector3
Without the initialisation values, only with the class name.
However, WHAT I WANT is to print something like this:
Vector3(x:4,y:4,z:4)
Hopefully,someone can help me with this! Thanks!
NOTE:I am fully aware that one can get the values of these properties by:
customVector.x //1
customVector.y //2
Currently the console is printing like this: Vector3 without the initialisation values, only with the class name.
This is because you did not tell Swift how exactly you want your instances printed when you interpret them as strings. Make your class conformant to CustomStringConvertible protocol and implement description to print what you need:
class Vector3 : CustomStringConvertible {
...
public var description: String {
return "Vector3(x:\(x),y:\(y),z:\(z))"
}
}

How to create shorthands for CGPoint & CGVector?

I'm doing a lot of positioning and animation stuff in literals, and they're taking up a lot of space and becoming unreadable because of the verbosity.
What I'd like to do is turn this
var xy = CGPoint(x: 100, y: 100)
Into this:
var xy = •(100, 100)
Similarly, I'd like to go from:
CGVector(dx: 200, dy: 200)
to something like this:
`(200, 200)
But I don't know how a macro-like shorthand or something like this would be done, or even if it could be done. Any pointers (puntendered) would be better than where I'm at.
I get that this is probably, for most people, less readable.
Due to the context I always know what these are. I don't need the parameter labels or function name to understand what I'm doing. And this is private animation and motion testing, there's no need for anyone else to ever understand what's going on.
extension CGPoint {
init(_ x: CGFloat, _ y: CGFloat) {
self.init(x: x, y: y)
}
}
extension CGVector {
init(_ dx: CGFloat, _ dy: CGFloat) {
self.init(dx: dx, dy: dy)
}
}
typealias P = CGPoint
typealias V = CGVector
let p = P(10, 10)
let v = V(10, 10)
But no idea about the • and ` part - I replaced them with P and V :)
For this type of thing you would likely use a typealias but I don't think you will be able to create types with names as operators or symbols.
See below, I created a typeAlias of CGP for CGPoint, you could simply just alias it to Point if you like.
Here is some information from the docs
A type alias declaration introduces a named alias of an existing type into your program. Type alias declarations are declared using the typealias keyword and have the following form:
typealias name = existing type
After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type.
EDIT
Two simple method of excluding the parameter names:
func cp(_ x: Int, _ y: Int) -> CGPoint {
return CGPoint(x: x, y: y)
}
let point = cp(0,2)
extension CGPoint {
init(_ x: Int, _ y: Int) {
self.init(x: x, y: y)
}
}
typealias CGP = CGPoint
let point2 = CGP(1,1)
The first method just creates a helper function which returns a CGPoint using it's designed intialiser. The second option is the better way of doing it, you extend CGPoint and add an intializer that marks the params as non-named params (by using the _ instead of the external name)
You can't use special characters as the compiler would not be able to differentiate between function names and operators like '*'.
Using typealias
using a typealias would allow you to shorten the function name but not omit the parameter names like you outlined in your question.
typealias p = CGPoint
//example
let p1 = p(x: 60, y: 60)
Using anonymous parameters
func p(_ x: CGFloat, _ y: CGFloat) -> CGPoint {
return CGPoint(x: x,y: y)
}
//example
let p1 = p(60, 60) //no parameter names
I too like to get rid of the parameter labels, but I don't advise reducing things to any briefer shorthand. I paste this code into the start of all my app projects:
extension CGRect {
init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
self.init(x:x, y:y, width:w, height:h)
}
}
extension CGSize {
init(_ width:CGFloat, _ height:CGFloat) {
self.init(width:width, height:height)
}
}
extension CGPoint {
init(_ x:CGFloat, _ y:CGFloat) {
self.init(x:x, y:y)
}
}
extension CGVector {
init (_ dx:CGFloat, _ dy:CGFloat) {
self.init(dx:dx, dy:dy)
}
}
That allows me to say things like CGPoint(1,4), and that's good enough, in my opinion.

Is there a specific way to use tuples as set elements in Swift?

I want to do set operations on co-ordinate pair elements from an x-y grid.
E.g. {(0,0),(1,4),(1,5),(2,3)} union with {(2,3),(1,4),(2,6)} = {(0,0),(1,4),(1,5),(2,3),(2,6)}
Unfortunately I can't work out a way of inserting tuples into Swift's Set commands as it says that they do not conform to the 'hashable' protocol.
Error: type '(Int, Int)' does not conform to protocol 'Hashable'
I believe I've got a work around but it involves a lot of code. Is there a simple way that I'm missing before I hit the grindstone?
Rather than using tuples to represent points, use the built in type CGPoint. You can extend CGPoint to be hashable by extending it:
import UIKit
extension CGPoint: Hashable {
public var hashValue: Int {
return self.x.hashValue << sizeof(CGFloat) ^ self.y.hashValue
}
}
// Hashable requires Equatable, so define the equality function for CGPoints.
public func ==(lhs: CGPoint, rhs: CGPoint) -> Bool {
return CGPointEqualToPoint(lhs, rhs)
}
Now that CGPoint is Hashable, you can use it in sets. For example:
let point1 = CGPoint(x: 0, y: 1)
let point2 = CGPoint(x: 0, y: 2)
let point3 = CGPoint(x: 1, y: 1)
let point4 = CGPoint(x: 3, y: 3)
let point5 = CGPoint(x: 3, y: 3) // Intentionally the same as point4 to see the effect in union and difference.
let set1 = Set([point1, point2 , point5])
let set2 = Set([point4, point3])
let union = set1.union(set2) // -> {{x 0 y 2}, {x 3 y 3}, {x 0 y 1}, {x 1 y 1}}
let difference = set1.intersect(set2) // -> {{x 3 y 3}}
You could make a struct as a Hashable type:
struct Point: Hashable {
let x: Int
let y: Int
}
Now that you have a hashable tuple, normal Set operations can be used:
let set1 = Set([
Point(x:0,y:0),
Point(x:1,y:4),
Point(x:1,y:5),
Point(x:2,y:3)
])
let set2 = Set([
Point(x:2,y:3),
Point(x:1,y:4),
Point(x:2,y:6)
])
let setUnion = set1.union(set2)
/*
setUnion = {
Point(x: 1, y: 5),
Point(x: 0, y: 0),
Point(x: 1, y: 4),
Point(x: 2, y: 3),
Point(x: 2, y: 6)
}
*/
Here you go:
class Pair {
var x: Int
var y: Int
init(x: Int, y:Int){
self.x = x
self.y = y
}
func isExisted(inPairs pairs:[Pair]) -> Bool {
for p in pairs {
if p.y == self.y && p.x == self.x{
return true
}
}
return false
}
static func union (pairs1: [Pair], pairs2: [Pair]) -> [Pair] {
var pairsFinal = [Pair]()
for p in pairs1 {
pairsFinal.append(p)
}
for p in pairs2 {
if !p.isExisted(inPairs: pairsFinal){
pairsFinal.append(p)
}
}
return pairsFinal
}
}
let pari1 = Pair(x: 4, y: 7)
let pair2 = Pair(x: 5, y: 2)
let pair3 = Pair(x: 4, y: 7)
let pair4 = Pair(x: 3, y: 9)
let pairs1 = [pari1, pair2]
let pairs2 = [pair3, pair4]
let f = Pair.union(pairs1, pairs2: pairs2)
And this is the result of the union: