Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
Pattern matching uses the ~= operator. It's buried in the Language Reference under Patterns. However the default implementation should succeed if the two objects are the same type and implement the == operator.

You need:

code:
@infix func == (lhs:C, rhs:C) -> Bool {
    return true
}
@infix func != (lhs:C, rhs:C) -> Bool {
    return false
}

class C : Equatable
{

}
Equatable is some magic sauce that succeeds as long as the global function == is defined, though in main.swift you need to define those first or the compiler will barf for reasons that rjmcall mentioned earlier in the thread.

Simulated fucked around with this message at 06:01 on Jun 28, 2014

Adbot
ADBOT LOVES YOU

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
rjmccall or any of you other Apple folks, if you get a chance can you review my scribblings about interop in Swift? Specifically: Unsafepointer<T>, including alloc and Unmanaged<T>. There is almost no documentation about how to actually deal with this stuff and I want to make sure I'm not giving out bad information.


Second question, why does Unsafepointer.dealloc take an int? Shouldn't it know its own size? or is this a concession to situations where you just receive an Unsafepointer<T> from some C API and the runtime has no idea what sizeof(T) is in that case?

Third and very minor note, the docs should call out that alloc should get sizeof(T), and the fact that sizeof exists. Oh and why you'd use sizeofValue vs sizeof.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

ljw1004 posted:

I'm trying to find in the iBook an explanation for the type system of named tuples...

code:
var t1 : (Int,Int) = (2,3)
var t2 : (a:Int, b:Int) = (2,3)
var t3 : (c:Int, d:Int) = (2,3)

t2 = t3 // disallowed
t1 = t3; t2 = t1 // allowed, loophole!
t2 = t3 as (a:Int, b:Int) // don't know; crashes Playground every time, and causes a build failure
Q. Are named tuples considered different types if they have different names? -- apparently yes.
Q. Is the unnamed tuple "t1" a different type from the named tuple type "t2"? -- presumably yes.
Q. Is there an implicit conversion between named and unnamed tuple types? -- apparently yes.
Q. Is there an explicit conversion between differently named tuple types? -- unknown


If you pass the values through a function, it works:

code:
func doit(fancy:(Int,Int)) -> (Int,Int) { return fancy }
func doitbetter(fancy:(Int,Int)) -> (a:Int,b:Int) { return fancy }
func doitfaster(fancy:(Int,Int)) -> (c:Int,d:Int) { return fancy }

t2 = doit(t3) //names removed to protect the guilty
t2 = doitbetter(t3) //no casting at all!
There is no explanation for the tuple type system as of yet.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

Thanks! Corrections made and evil function reference removed. I'm glad you mentioned that, I was actually going to do a post about the truly awful things you can do with it but I'm gonna skip it.


Anyone have issues trying to use a framework that includes Objective-C and Swift mixed code? In the project where I'm trying to use the framework, I kept getting errors about the Objective-C (project level) headers not being found, via the swift-bridging-header.h file (again set to project). I ended up having to stick a preprocessor macro in there and #if out the includes from the bridging header unless the framework itself is being compiled. I have the bridging header set as project as well, and verified it does not appear in the .framework directory, but somehow it is being referenced anyway.

It apparently works just fine from what I can tell - I'm able to use stuff from my framework without issue... it just feels wrong.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
code:
users-mac:Debug user$ xcrun swift
  1> func yesNo<T>(wat:(T)->LogicValue, val:T) -> String {
  2.     if wat(val) {
  3.         return "YES"
  4.     } else {
  5.         return "NO" 
  6.     }
  7. }   
Segmentation fault: 11
users-mac:Debug user$ 
Thanks, I'll be here all week :rimshot:
(rdar://17499275)


edit: Crash Golf. The shortest line able to crash the compiler:

code:
users-mac:Debug user$ xcrun swift
Welcome to Swift!  Type :help for assistance.
  1> if true as LogicValue {}
Segmentation fault: 11
users-mac:Debug user$ 

Simulated fucked around with this message at 17:26 on Jun 29, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
I'm starting to see more and more issues with how protocols use the abstract type alias, or at least some of the limits around them. It effectively erases some of the type parameters, making the protocol itself useless as a type specifier for anyone except the library writer implementing the protocol.

Given these definitions from the standard library:

code:
protocol Generator {
    typealias Element
    func next() -> Element?
}
protocol Sequence {
    typealias GeneratorType : Generator
    func generate() -> GeneratorType
}
protocol Collection : Sequence {
    subscript (i: Self.IndexType) -> Self.GeneratorType.Element { get }
}
struct Dictionary<KeyType : Hashable, ValueType> : Collection, DictionaryLiteralConvertible {
    typealias Element = (KeyType, ValueType)
    typealias Index = DictionaryIndex<KeyType, ValueType>
}
We can see that the associated types are being effectively used to abstract over Element and Index so that when you specify a Dictionary<String, Int>, Element becomes a tuple (String, Int), Collection's Index is DictionaryIndex<KeyType,ValueType>, and everything flows together.

The problem is I can't use Sequence at all because it has only the abstract associated types:

code:
let d = ["str":5]
var s:Sequence = d

let gen = s.generate() //compiler error: Sequence does not have a member named 'generate'

var s2 = SequenceOf<(String, Int)>(d) //workaround
Something seems very wrong about this. It looks like the library has a bunch of structs to paper over this by letting you stuff a Sequence concrete implementation into a SequenceOf<T>. That requires ghosted structs to dupe the protocols and requires that I re-specify the type information that Dictionary already had. It also appears I can't use the protocol as a return value in some cases. In my unit tests I kept having to create a new SequenceOf<T>(array) to be able to actually use an array where I had wanted an abstract Sequence. I shouldn't have to construct a new object just to use Array as a Sequence, a protocol it already conforms to.

Why doesn't "var s:Sequence = d" give me a "Sequence<ElementType == (String, Int)>", with the abstract types made concrete?

For that matter, why can't I do "var s2 = SequenceOf<Any>(d)"? A tuple is certainly a kind of Any.


I'm sure I am not the first to make this argument, nor made it as clearly or cleverly as someone else. I also get why abstract type aliases can be a good thing, to avoid having to give a bunch of extra type parameters to Dictionary in this example, or implementing a bunch of nested interfaces ala C#. It just feels like there is something missing here and all those concrete structs are a sign that something went wrong in the type system somewhere.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

eschaton posted:

I think that was referring to filing intentional duplicates to try to inflate priority, like "this bug is a duplicate of 12345, here's some text copied and pasted from a web site, I vote for this feature too!"

If you are yourself running into a bug or other difficulty, you should always file it, and not worry about whether what you're filing is a dup of something else. (Only don't if you know your exact issue is already known and you've been asked not to—like, say, for access control in Swift.)

Also, don't get caught up spending hours putting together a bug report, a couple sentences is fine if that's all you actually need to specifically describe the issue. If an engineering team needs more detail they'll ask. And push back if a bug comes back to you as fixed but from your perspective it's not.

Finally, if you would like to see a feature/enhancement/change, you should also always file it yourself, and explain your needs clearly; they may not be addressed the way you requested, but they will be taken into account. (This is the reason "why" matters, not just "what.") An example of that from early OS X history was when some developers asked for the Enterprise Objects Framework to be brought forward; what they got was Core Data instead, as a model-level persistence framework for Cocoa.

A few of my Swift bugs were closed as dupes (see below). I'd have to login to check but the other ~20 are sitting there, unexamined, with zero information since the day I filed them. It's been nearly a month. This includes swift compiler hard crash and eternal loop bugs with attached repro cases and crash reports. A simple "tested and reproduced" acknowledgement would be at least minor encouragement. For compiler bugs, Apple should have had some interns whip up a code submission system linked to the bug reports that would allow us to upload sample projects, then run them inside a VM snapshot to immediately verify that the code crashes or loops eternally, roll back the snapshot, then move on to the next submission. A farm of a hundred machines could churn their way through the submissions, probably even at night using spare cycles in existing data centers. Any bug that reproduces a crash could then be cross-checked with existing crashes automatically to determine hot fault paths. The ways the system could be improved are endless.

* The big problem with duplicates is that since radar is not public, there is an intermediate window in which a bug is not widely known enough to show up on stackoverflow in google searches, but is far more than a one-off, leading to thousands / tens of thousands (or more) wasted effort by we non-Apple folks to create reproducible test cases and fill out bug reports. That experience is highly demotivating.


I endure Apple's bug tracker because it's the one small way I can repay rjmccall's kindness and awesome technical postings over the years. There is nothing positive or pleasant about the experience.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

dizzywhip posted:

I think I finally hit Xcode's breaking point. I can edit code for a few seconds before it crashes, locks up for minutes/indefinitely, or Source Kit Services errors out over and over. Hopefully the next update brings some significant stability improvements. I was still enjoying it even when it was barely usable though, I'm super excited to start transitioning over to Swift full-time for 1.0.

If certain constructs are present in the code, any partially typed out statement, unmatched braces, half-complete type name, etc will trigger a SourceKit crash for me. I just ignore them; I have a log directory of hundreds (maybe thousands now) of crash reports.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
rjmccall - is there a sanctioned way to cast a C struct? e.g. sockaddr which is treated kinda like a union with sockaddr_in, sockaddr_in6, etc. Other than the verbotten function we've previously discussed, I couldn't find a way to convince swift that an UnsafePointer<sockaddr> is really an UnsafePointer<sockaddr_in>. edit: Answered my own question, it's UnsafePointer<sockaddr_in>(pointerToSockaddr) which just casts the pointer types.


2. What's the difference between UnsafePointer's dealloc and destroy?

3. In idiomatic Swift, for a buffer to receive some data like char or Int8, I'm using UnsafePointer.alloc, but I saw an ArrayBuffer class and one can always use an array itself. Is there a simple preferred way to say "make me a UTF8 character buffer X bytes long"? Or is it mostly dealer's choice?

Simulated fucked around with this message at 22:13 on Jul 19, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

ljw1004 posted:

rjmcall, I really appreciate all your posts in this thread. I haven't yet figured out how to use radar, but I'll do that tonight or tomorrow night and file all the bugs I've posted here so far. Am still completely new to Apple development.

On bugreport.apple.com login and create a new bug (using the now modern iOS 6 UI! At least it isn't original Aqua). Select Developer Tools (it's the Xcode 6 icon).

Much of the stuff it asks about is completely arbitrary because there is no option for "Xcode" vs "Swift compiler" vs "Playgrounds" vs whatever else. It all just goes in the dev tools bucket.

I usually put Swift: in my subject. Down below in the configuration I just put "Xcode 6 Beta X".

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

lord funk posted:

Can you quick explain this? I'm falling behind in my Swift blog reading / version updates.

Speaking of, which blogs are you all reading?


http://www.weheartswift.com/one-month-swift/ has a bunch of links

Obviously https://developer.apple.com/swift/blog/ is a good one to watch

http://andelf.github.io always posts interesting stuff but I have to read it through Bing translate because he mostly posts in Chinese. He's got some posts with dumps of the swift standard library and his github page is my secret sauce for poking at the internals.

Mike Ash is covering Swift topics now https://www.mikeash.com/pyblog/

And Brent Simmons does some too http://inessential.com

David Owens II has some great stuff https://medium.com/@owensd/latest


And there's mine :v:

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

ljw1004 posted:


rjmcall Please remove this feature, and instead implement a method ".HasValue" on Optional<T>. That way we can write code that's easy to read:

code:
if x.HasValue {...}

if y.HasValue {...}

I implemented these extensions for similar reasons and the fact that 9/10 times I just want to provide an alternate value, I don't really care if it is nil.

code:
extension Optional {
    func valueOrDefault(defaultValue:@auto_closure ()->T) -> T {
        return apply(self!, defaultValue())
    }
    
    var hasValue: Bool {
    get { return apply(true, false) }
    }
    
    private func apply<U>(caseSome:@auto_closure ()->U, _ caseNone:@auto_closure ()->U) -> U {
        switch(self) {
        case .Some:
            return caseSome()
        case .None:
            return caseNone()
        }
    }
}

var s:String? = nil
let s2 = s.valueOrDefault("alt")

if s.hasValue {
    println("Has value!")
}
This guy also provides an operator to perform a similar function as C#'s "??":

code:
operator infix ||| {}

@infix func |||<T> (left: T?, right: T) -> T  {
    if let l = left { return l }
    return right
}

@infix func |||<T,V> (left: T?, right: V) -> Any  {
    if let l = left { return l }
    return right
}

Simulated fucked around with this message at 18:36 on Jul 23, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
rdar://17782662 filed to add the ability to export a module's internal members to another specified module. This makes unit tests on internal members much easier and allows two modules by the same developer to cooperate as if they were the same module, but without making that part of the public API.

See also: http://www.russbishop.net/swift-testing-privates

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
This is the second time I've started writing this horrible abomination... if I don't get some real reflection soon I won't be able to stop myself from unleashing it upon the world. I am going to get the type's members and their type names one way or another.

Also the unknowns are suspiciously in the executable region; brute forcing the function call didn't work but I found someone who figured out the function call trampoline and associated structs. When I get back from dinner that's my next horrible, horrible step.

I'm going to put functions inside a dictionary and invoke them later if it kills me.

code:
struct _MagicMirrorData {
    let owner: Int = 0
    let ptr: Int = 0
    let metadata:Any.Type = Any.self
    
    let unknown1: Int = 0
    let unknown2: Int = 0
}

struct _ClassMirror {
    let data:_MagicMirrorData = _MagicMirrorData()
}

let instance = Mine()
let mirror = reflect(instance)

let key = mirror[0].0
let value = mirror[0].1

//HORRIBLE
let horrible:_ClassMirror = reinterpretCast(value)
horrible.owner //actually swift NativeObject
horrible.ptr //RawPointer to ExistentialMetatype


//less horrible BUT STILL HORRIBLE
@asmname("swift_stdlib_getTypeName") func _stdlib_getTypeNameImpl<T>(value: T, result: UnsafePointer<String>)
let buf = UnsafePointer<String>.alloc(1)
_stdlib_getTypeNameImpl(key, buf) //mangled name
P.S. I'm moving to the SF/Bay area soon, joining a startup and moving to iOS full time. Can I be part of the cool kids club now?

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

Flobbster posted:

Enjoy the huge rent. :v: I thought I could escape it in San Jose (and did for a year!) but it eventually caught up down here too. Now there's no escaping it.

Oh yes, it's crazy. I'm going to try to buy if possible. I just can't pay 3000-4000 a month for an apartment and end up with nothing for it.

That said, I have no idea how difficult it is to get a mortgage out there and I hear stories of people coming in with all cash offers, so that's scary too.

Simulated fucked around with this message at 01:51 on Jul 25, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
edit: I see what is happening here; those things are @auto_closures and the compiler is breaking down the AST (presumably) and doing other fancy strangeness so you can't actually do anything about it.

Simulated fucked around with this message at 05:40 on Jul 29, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

quote:

operator infix !! { associativity left }

@infix public func !!<T>(left: T?, right: T?) -> T? {
return left ? left! : right
}

@infix public func !!<T>(left: T?, right: @auto_closure ()->T) -> T {
return left ? left! : right()
}

var x:String?
var y:String?
let z = "alt"

let a = x !! y !! z

Is there any reason this shouldn't work? The compiler complains that no overloads take the supplied arguments which is incorrect. In theory it should be using the first on x !! y, which produces an optional and so the second would be called with that result and z. If you move "alt" inline the compiler complains about converting a StaticString to String.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
Ok, rdar://17842481 filed

Edit: autocorrect :mad:

Simulated fucked around with this message at 18:45 on Jul 29, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
I did a horrible, horrible thing

code:
@asmname("swift_demangleSimpleClass") 
func demangleSimpleClass(mangledName: ConstUnsafePointer<Int8>, 
     moduleName: UnsafePointer<Int>, 
     className: UnsafePointer<Int>) -> Bool

let someInstance = ...
let namen = object_className(someInstance)

let p2 = UnsafePointer<Int>.alloc(1)
let p3 = UnsafePointer<Int>.alloc(1)

let ret = demangleSimpleClass(namen, p2, p3)

if ret {
    let p2_2 = UnsafePointer<Int8>(p2.memory)
    let p3_2 = UnsafePointer<Int8>(p3.memory)

    let moduleName = String.fromCString(p2_2)!
    let className = String.fromCString(p3_2)!

    println("Type Name: \(moduleName).\(className)")
} else {
    println("Failure")
}

p2.dealloc(1)
p3.dealloc(1)
:stare:

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice


:eng99:

To be fair, I did try something like that but forgot I declared them "let" and the compiler just gave me another "cannot convert to @lvalue $T###" sort of message. I filed rdar://17857686 to ask that Swift output something like "Cannot pass 'let' constant reference to parameter expecting mutable 'inout'". I'm sure you already have a ton of bugs related to type conversion error messages since they're all pretty much like that in beta 4.

So what I'm saying is I take no responsibility for my own failures and blame it all on you :v:


P.S. Is there any way to get the type names/descriptions that the REPL will spit out? (i.e. find out that i's type is Swift.Int)

pre:
Welcome to Swift!  Type :help for assistance.
  1> let i = 5
i: Int = 5
  2> let mirror = reflect(i)
mirror: _LeafMirror<Int> = {
  _value = 5
  summaryFunction =
  quickLookFunction =
}
  3> mirror.valueType
$R0: Any.Type = Swift.Int 

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

Kallikrates posted:

The example is derived..., the object implementing the protocol is not a plain NSObject. On the API consumer side, knowing its class X implements protocol Y is helpful when you want to call functions of class X and protocol Y without having to cast back and forth between "id<Foo>" and "X" when I get back to my computer with Xcode Beta ill try (protocol<NSObject, Foo>) but I don't think its a solution because the NSObject protocol only exists for base NSObject, not subclasses,

Another example:
code:
extension CustomNSOperationClass {
  func returnsSomethingThatConforms() -> (CustomNSOperationClass, FooProtocol) {

  }
}
//given the return type no as? should be needed
CustomNSOperationClass.returnsSomethingThatConforms().start().fooProtocolMethod()
The major use case is extensions/categories that add protocol conformance.

Another option would be to create a protocol of all the public methods/functions of a class and then use protocol composition, but that's not necessary in Obj-c so I don't think it should be needed in Swift.

First you don't use NSObject, you use NSObjectProtocol because in Swift you can't name them the same thing since the type names would be ambiguous.

Second, this works just fine assuming Foo is a protocol:

code:
func returnConformable() -> (protocol<NSObjectProtocol, Foo>)
And indeed, Swift will infer that the return type supports all the properties and methods/selectors on both.

If you are talking about identifying the return type as being an instance of class X while also implementing protocol Y, then you can use a generic method:

code:
func returnConformable<T:MyClass where T: Foo>() -> T
But you'll have to declare MyClass' conformance to Foo or it won't compile, in which case you already have the definition of MyClass visible and it becomes pointless.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
code:
func takeFive<T:IntegerArithmeticType>(a:T)(b:T)(c:T)(d:T)(e:T) -> T {
    println("{a=\(a), b=\(b), c=\(c), d=\(d), e=\(e)}")
    return a + b + c + d + e
}

let f1 = takeFive(5)
let f2 = f1(b: 4)
let f3 = f2(c: 3)
let f4 = f3(d: 2)
let f5 = f4(e: 1)

let ret = takeFive(5)(b:4)(c:3)(d:2)(e:1) //15

println("\(f5) vs \(ret)")

swiftc posted:

{a=5, b=1, c=1, d=1, e=1}
{a=5, b=4, c=3, d=2, e=1}
9 vs 15

Wat :what:


edit: this works just fine
code:
func takeFive(a:Int)(b:Int)(c:Int)(d:Int)(e:Int) -> Int {
    println("{a=\(a), b=\(b), c=\(c), d=\(d), e=\(e)}")
    return a + b + c + d + e
}
So does doing it manually:

code:
func takeFive<T:IntegerArithmeticType>(a:T) -> (T->(T->(T->(T->T)))) {
    return { (b:T)  in
        return { (c:T) in
            return { (d:T) in
                return { (e:T) in
                    return a + b + c + d + e
                }
            }
        }
    }
}
Also, the docs do not specify that an argument name is required for curried functions but they are. Attempting to specify "_ b" gives a warning that the argument is not named but in either case it requires the caller specify the name.

rdar://17973350 and rdar://17973340

Simulated fucked around with this message at 05:36 on Aug 11, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
rjmccall: I just now realized that your team removed @conversion/__conversion.

There is not enough room to describe my hate at this moment.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
Basically create a transparent wrapper that can degrade to the wrapped type without having to refactor a bunch of code with useless glue. (It was @conversion that made me think it might be a legit feature.) It's not really hate, I was just getting frustrated trying to write a new class in Swift and call it from Objective-C, I kept running into issues like defining enums in Swift, etc.



I also just ran into a case where I greatly miss the ability to say "yes, yes compiler... I know this isn't technically safe, but trust me, class X totally has private members with definition A,B,C so please let me break the rules". The Alamofire library implements didReceiveChallenge and does its own SSL verification. It does not expose the delegates, nor any way to handle that. I am connecting to a system using a self-generated certificate that I know how to validate, but there is no way for me to do so. This is just an example, it could be any situation.

If this were Objective-C, I would just declare my own header for the private delegate class and/or swizzle the method and make it work, without having to maintain my own fork of Alamofire (or worse, not having the source).

If this were C#, I would use runtime IL generation (or the newer Expression<T> stufF) to create a dynamic method and patch it in, or possibly use reflection to grab and set private fields.

Are both of those things hacks? Certainly. Are they absolutely necessary at times, including to work around bugs in system frameworks? Yup. I know that I can assume @objc objects derived from NSObject are usable with the standard Objective-C runtime calls, I just wish Swift had a native way to do it. It can be a pain with big fat "warning: at your own risk" on it, but it should exist. (think "unsafe{}" blocks in C#, which IIRC the default csproj disables so you have to explicitly take responsibility for it)



While I'm complaining, is there not a syntax to combine boolean logic and optional unwrapping in one if statement, or even multiple optional unwraps?

code:
if let x = maybeX, y = maybeY, var z = maybeZ { }

if let x = maybeX && butts > farts { }
I also find myself desperately wanting a concise way to express "if this optional is non-nil, then see if it responds to selector/defines method X, if so call it, else pretend the whole thing was nil". Instead I'm doing:

code:
if let obj = notification?.object { 
    if obj.respondsToSelector(Selector("hey")) {
    }
}
I would file radars but I already have a queue of 20 to go verify as fixed and still haven't unpacked everything.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

rjmccall posted:

Can you express that method check using an optional method somehow? If so, it should be as concise as:

Swift code:
notification?.object.hey?()
I'll try to unpack/forward the rest of this later.

No, I don't think so. It throws doesNotRecognizeSelector if object doesn't implement hey. I'll double check tonight though.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
code:
// Playground - noun: a place where people can play

import UIKit
import XCPlayground

XCPSetExecutionShouldContinueIndefinitely()

let kMyNotification = "Butts"

@objc class Wat : NSObject, WatProtocol {
}

@objc protocol WatProtocol : NSObjectProtocol {
    optional func lolers()
}

NSNotificationCenter.defaultCenter().addObserverForName(kMyNotification, object: nil, queue: nil) {
    (notification) -> Void in
    //ERROR: AnyObject does not have a member named 'lolers()'
    //println("Wat = \(notification.object?.lolers?())")

    if let oops = notification.object as? WatProtocol {
        //Prints Wat = nil, yay!
        println("Wat = \(oops.lolers?())")
    }
}

let myObj = Wat()
NSNotificationCenter.defaultCenter().postNotificationName(kMyNotification, object: myObj)
Indeed, you cannot use optional method chaining except with protocol optional methods, which makes it fairly useless (or requires a ton of boilerplate extensions).

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

rjmccall posted:

Huh. It should definitely be letting you ask for that method with AnyObject-based dispatch. That's a bug.

As a workaround, try just throwing @objc on the implementations of that method that you're hoping to find.

It turns out that Swift demands the selector exists on some protocol somewhere visible to it, then it will allow it. No need to cast or anything, the selector must simply exist.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

rjmccall posted:

Oh. Yeah. That's true in ObjC, too.

I thought it only requires the selector to exist anywhere, not specifically in a protocol?

Also: my kingdom for a way to get the list of possible values for an enum (and the list of associated types for each one if any).

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

rjmccall posted:

Yes. Is that not true in Swift? If you've declared it somewhere, and exposed it to ObjC with @objc, that's worth a bug.

You know what I just re-tested it and it appears to, but it was not working in my real project. I may have some header madness screwing things up.


quote:

It's on the bucket list. Er, at least the list of possible values for payload-less enums is. Meaningfully enumerating payloaded enums would probably require static or dynamic metaprogramming; what's your goal?

Bridge swift enums to Objective-C so when I create entirely new functionality in Swift (that needs to be consumed by old ObjC classes), I don't have to drop back to ObjC just to define an old-fashioned NS_ENUM.

For basic raw enums with no functions that inherit from NSInteger or some other integral type obviously Swift could just emit the appropriate C-style enum even though it doesn't today, but I think it makes more sense to expose them as objects.

eg:

code:
@objc enum YouDontSay {
    case WellINever(String)
    case HowDareYou(Int, Int)
    func HitMe() { }
}
translates to:

code:
@interface YouDontSay : NSObject
+ (YouDontSay *)wellINeverWith:(NSString *)value1;
+ (YouDontSay *)howDareYouWith:(NSNumber *)value1 and:(NSNumber *)value2;
- (BOOL)isWellINeverInstance;
- (BOOL)isHowDareYouInstance;
@property (readonly, nonatomic) NSArray *values;
@end
So on the Objective-C side it may be ugly, but you can construct "boxed" enumeration values, get values out (by examining the array), determine which enum value you have, etc. Obviously you could design it a bit differently (subclasses for the different cases or something), but that's the general concept. If I had that kind of metaprogramming capability at runtime or compile time (ala Rust macros) it would be totally doable.

So that and @protocol circular header references are the two really annoying pain points right now. A class which needs to be included in my bridge header also needs to implement a protocol defined in swift. Oops, no-can-do buster! So I end up with Objective-C files that shadow half my Swift classes just to declare protocols and enumerations.


I also ran into this hilariousness:

code:
//ObjC code in some stupid VC somewhere
- (void)viewDidAppear:(BOOL)animated
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        MyViewController *vc = [[MyViewController alloc] initWithValues:@[@"yes", @"no", @"maybe"]];
        [self.navigationController pushViewController:vc animated:YES];
    });
}

//Fancy new swift VC
@objc class MyViewController : UIViewController {
    var someArray:[String]?
    required init(values:[String]) {
        self.someArray = values
        //cool, someArray has three values!
        println("someArray.count = \(someArray?.count)")
        super.init()
    }

    //Swift claims this is required, wtf?
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    //fun
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    
    //OOPS, someArray is nil!
    override func viewDidLoad() {
        println("someArray.count = \(someArray?.count)")
    }
}
That's right, the values set in the initializer are blown away after initialization is done. Guess what happens if someArray is not nillable? Crash!

I boiled it down to the simplest case and it appears that calling super.init() instead of super.init(nib,bundle) triggers the failure in initialization. If you call super.init() and don't implement override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) you get a nice crash concerning an unimplemented initializer.

OK you say, you're calling the wrong initializer for a view controller... Well smartypants, guess what happens if you inherit from UITableViewController and call super.init(style:UITableViewStyle) like a normal person? It behaves as if you had called super.init(), complete with crashes and missing values.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

rjmccall posted:

That is a really interesting idea, and I have no idea what to tell you. Metaprogramming, I guess.


Yeah, so the issue here is that init() is not the designated initializer for UIViewController, and that hasn't been marked in the headers, so we have to be conservative and assume you know what you're doing. Don't super-delegate to a non-designated initializer.


Ugh. This is so screwed up. The problem is that initWithStyle: does not behave like a designated initializer for UITableViewController, because it doesn't call a designated initializer from its superclass: it calls init, which on UIViewController is a convenience initializer which re-dispatches down to the most-derived class's initWithNibName:bundle:. So, basically, initWithStyle: is not a designated initializer, and when you're super-delegating, you need to be calling the designated initializer, which is initWithNibName:bundle:. I'm sorry this isn't (1) documented and (2) properly annotated in the header.

You can't directly set the style so there is no possibility of calling some other initializer. That makes it impossible to have a UITableViewContoller-derived subclass in swift with an initializer... unless you're banning grouped table views :v:

rdar://18747436

Simulated fucked around with this message at 08:28 on Oct 23, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
code:
// Playground - noun: a place where people can play
import Cocoa

@objc class HiHo : NSObject { }
@objc class OffToWorkWeGo : HiHo { }
func OkilyDokily() -> OffToWorkWeGo? { return nil }
func Wat() -> (OffToWorkWeGo?, NSError?) { return (nil, nil) }

var wat:HiHo?
var err:NSError?

wat = OkilyDokily() //okily-dokily!

(wat, err) = Wat() //Cannot express tuple conversion, you jerk
Totally safe upcast? That's cool.

Oh wait, in a tuple? gently caress right off. rdar://18792507

Also confirmed rdar://18747436 is still alive and well in 6.1.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
Today's random bug rdar://18807413 AKA "7 is a magic number":

code:
let v1:String? = nil
let v2:String? = nil
let v3:String? = nil
let v4:String? = nil
let v5:String? = nil
let v6:String? = nil
let v7:String? = nil
let v8:String? = nil
let v9:String? = nil

if let x = v1 ?? v2 ?? v3 ?? v4 ?? v5 ?? v6 ?? v7 ?? v8 ?? v9  { }
With 6, performance gets very slow. With 7, it takes a minute to execute. At 9, my laptop turned into a space heater.


Trying to do serialization/deserialization has me very nearly tossing this Swift code out and doing it in Objective-C. There's probably a better way that I just can't see right now, but so far its just a lot of manual ["key" : self.key] crap everywhere, and the inverse on the other side. I was trying to coalesce all the json-swift JSValue.errors to see if any errors are present. It was working great up until I hit a larger class.

The funny part is in C# I would just use the JSON serializer and literally be done in five minutes; it would automatically map read/write properties bidirectionally, handle arrays/dictionaries, nested values, etc.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

fleshweasel posted:

The reason is simply that it allows for chaining and reduction of nil checks.

code:
if let foo = object.optionalProperty?.child.methodWhichReturnsAnOptional() {
}
as opposed to

code:
if let foo = object.optionalProperty {
    if let bar = foo.child.methodWhichReturnsAnOptional() {
    }
}
Although I maybe am not expressing the exact situation where an extension on an optional would be useful, I think you can see where it would be. Equivalents to .NET's string.IsNullOrEmpty() and IEnumerable.any() would probably be really common.

Not that I disagree - I too have run into situations where extending SomeType? would be useful - but you can already chain optional method invocations that way.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

Flobbster posted:

I'm always happy to wait for a well-designed general feature than a specific hack :) I'm really looking forward to what Swift brings to the table w.r.t. generics overall. From what I've already seen in the standard library and what you've talked about wanting to do, I'm hoping that we're going to start getting a lot closer to the power of C++ templates than a lot of other modern languages since then (at least as close as you can get without doing the same substitution-only approach used there).

On that note, I was recently trying to write a generic matrix ADT that would have a fixed size at initialization time, but when I tried to fill the array using the (count:repeatedValue:) initializer, I hit a stumbling block:

code:
class Matrix<T> {
    private let values: [T]

    init(rows: Int, cols: Int) {
        values = [T](count: rows * cols, repeatedValue: T())
    }
}
This obviously fails because there isn't enough information about T to know that it can be parameterlessly-initialized, and a protocol constraint wouldn't help here. Do you have thoughts about this (something similar to concepts?) in your future roadmap?


This is equivalent to the "new" constraint in C# and I second the motion.

Also big news: very shortly we will be shipping our first Swift code. Other than a few pain points the overall experience makes writing Objective-C seem like COBOL already.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
OK this UIViewController initializer stuff is starting to really drive me crazy. I can't ever create UIViewController subclasses with required properties because it forces me to override initWithCoder and I can't/don't have any useful values to provide in that scenario. That means making constants (let) into optional var properties, which means useless let propName = self.propName! in all my methods. Or just creating a broken init(coder:), heh.

That said, I'm starting to default to writing all new code in Swift and I like it. We should be shipping our first Swift code into production shortly.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
I am running into a real pain... when thinking about background downloading, it should be obvious that the entire object graph can be gone when the app resumes and the download task is ready. That means I need to figure out what root object I need and walk the chain of selectors to find the appropriate model to notify so it can update itself. Trying to do this in Swift is really annoying due to lack of any way to invoke methods from a string, even when everything is @objc (aka performSelector isn't imported).

Obviously I can work around it by creating utility functions in Objective-C but that just smells wrong.

edit: I'm pretty sure getting the IMP and casting through UnsafeMutablePointer/CFunctionPointer can't possibly work.

edit2: Well it doesn't work but I can't figure out what I'm doing wrong, because IMP is just a C function pointer and the first two parameters are pointers (id,SEL). Doing the exact same thing with a plain Swift function works fine, I can brutally cast it and make it work as a C function pointer. Doing that with an IMP out of methodForSelector: always barfs.

Simulated fucked around with this message at 01:34 on Nov 19, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
I guess arrays of closures are not objects?

code:
func synchronized<T>(context:AnyObject, f:()->T) -> T {
    objc_sync_enter(context)
    let result = f()
    objc_sync_exit(context)
    return result
}

typealias OperationBlock = ()->()
var ops:[OperationBlock] = []
let hah = synchronized(ops) {
	return hah.count
}
pre:
Type '[OperationBlock]' does not conform to protocol 'AnyObject'
Actually that's only if you bail on the return types altogether. The actual error is
pre:
Cannot invoke 'synchronized' with an argument list of type '(@lvalue [OperationBlock], () -> () -> $T3)'
Worked around it by boxing the closure.

Simulated fucked around with this message at 00:23 on Dec 20, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

rjmccall posted:

Closures aren't objects, and so arrays of closures aren't arrays of objects. Arguably we could make this work, since we do allow our native closure type to be implicitly converted to block type, but we don't currently.

...that said, don't do what you're doing. We will convert our native arrays to an object type, but we are not promising that you'll get a consistent object back, especially if you're making structural changes to the array. So it's really, really not appropriate to use as a lock.

Yeah I realized it was a fool's errand, I was just curious why it wouldn't promote them to blocks

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
Let's assume I am trying to create a wrapper for a protocol with associated types.

code:
protocol Food { }
class Grass : Food { }

protocol Animal {
    typealias EdibleFood //:Food <--- BOOM
    func eat(f:EdibleFood)
}
class Cow : Animal {
    func eat(f: Grass) { }
}

struct SpecificAnimal<F:Food> : Animal {
    let _eat:(f:F)->()
    init<A:Animal where A.EdibleFood == F>(var _ selfie:A) {
        _eat = { selfie.eat($0) }
    }
    func eat(f:F) {
        _eat(f:f)
    }
}
Why does constraining Animal's EdibleFood abstract type give Swift an absolute hissy fit on SpecificAnimal? It will freak and say that F is not a Food when the constraint on the struct clearly says it is.

Adbot
ADBOT LOVES YOU

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

rjmccall posted:

I don't know, that seems like it should work. Did you try defining typealias EdibleFood = F explicitly? That shouldn't be necessary, but I know that our logic for inferring those associated types has some bugs in it, basically because it's trying too hard to do everything at once.

Doesn't appear to work. Created rdar://19371678

  • Locked thread