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
rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
It probably shouldn't be inferred at all, frankly. We added a lot of implicit conversions to object types to try to making ObjC bridging feel clean, and they've been causing tons of problems like this.

Adbot
ADBOT LOVES YOU

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
pre:
Bitcast requires both operands to be pointer or neither
  %43 = bitcast %objc_object* %42 to %PSs9AnyObject_, !dbg !379
Stored value type does not match pointer operand type!
  store %PSs9AnyObject_ %43, %objc_object** %44, align 8, !dbg !379
 %objc_object*LLVM ERROR: Broken function found, compilation aborted!
Command /Applications/Xcode6-Beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift failed with exit code 1
code:
    var context: AnyObject? {
    get {
        let ptr = dispatch_get_context(_queue)
        if ptr != nil {
            let unmanaged:Unmanaged<AnyObject> = Unmanaged.fromOpaque(ptr)
            //return unretained value so we dont change retain count
            return unmanaged.takeUnretainedValue() //CRASH CITY <----
        }
        
        return nil
    }
    set {
        //grab old value so we can clean it up
        let oldPtr = dispatch_get_context(_queue)
        
        //do an unbalanced "retain" so the object will stay alive
        //we are responsible for eventually releasing somewhere
        if newValue {
            let ptr = Unmanaged.passRetained(newValue!)
            dispatch_set_context(_queue, ptr.toOpaque())
        } else {
            dispatch_set_context(_queue, nil)
        }
        
        //cleanup the old value
        if oldPtr != nil {
            let unmanaged:Unmanaged<AnyObject> = Unmanaged.fromOpaque(oldPtr)
            unmanaged.release() //balance out the retain we did when originally set
        }
    }
    }
I'm telling it that I've got an Unmanaged<AnyObject>. What's crazy is this exact same code works fine in ThreadLocalSlot<T:AnyObject>. rdar://17492202


Also, "error: unimplemented IR generation feature non-fixed class layout" is getting really old.

Simulated fucked around with this message at 00:46 on Jun 28, 2014

ljw1004
Jan 18, 2005

rum
How do you switch on an optional type? I tried this...

code:
let x : String? = nil

switch x {
    case nil: println("nil")
    case "fred": println("fred")
}
The "case nil" gives an error saying that the operator ~= isn't defined "on the supplied arguments". I guess I'd expected it to be implicitly defined at least for this case...

The "case fred" actually gives an error asking if I'd meant to write ? or ! but I'm not sure where I'd write it...

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

ljw1004 posted:

How do you switch on an optional type? I tried this...

code:
let x : String? = nil

switch x {
    case nil: println("nil")
    case "fred": println("fred")
}
The "case nil" gives an error saying that the operator ~= isn't defined "on the supplied arguments". I guess I'd expected it to be implicitly defined at least for this case...

The "case fred" actually gives an error asking if I'd meant to write ? or ! but I'm not sure where I'd write it...


I don't know if this is the best way, but:

code:
var s:String? = "fred"

switch s {
case let x where x == "fred":
    println("hi")
case let x where x == nil:
    println("nillllll")
default:
    println("i have no idea")
}
I too thought there must be a way to case out a switch with an optional but I didn't see one.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
code:
switch x {
    case .None: println("nil")
    case .Some("fred"): println("fred")
    case .Some(let x): println("other: " + x)
}

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
Apparently one of my favorite generics casting tricks from C# didn't make the transition to Swift because you can't specialize a generic function (aka provide the type parameter explicitly):

code:
    func getContext<T:AnyObject>() -> T? {
        return self.context as? T
    }

let o = getContext<String>()
I also find myself having to write annoying things like this:

code:
let x:SomeGenericType<I_Am_A_Type> = SomeGenericType()
I think you should be allowed to specialize a generic type or function, at least in these two cases. Are there any downsides?

Axiem
Oct 19, 2005

I want to leave my mind blank, but I'm terrified of what will happen if I do
Holy poo poo, I somehow missed the point that optionals are enums under the hood :monocle:

ljw1004
Jan 18, 2005

rum

Plorkyeran posted:

code:
switch x {
    case .None: println("nil")
    case .Some("fred"): println("fred")
    case .Some(let x): println("other: " + x)
}

Thanks!

I'm still having trouble with switch statement. I tried to type out the example from the "Introduction to Swift" talk:

code:
    @IBOutlet var executeButton: UIButton
    @IBOutlet var firstNameTextField: UITextField
    @IBAction func didTap(sender: AnyObject) {
        switch sender {
            case executeButton: println("you tapped execute")
            case firstNameTextField: println("you tapped firstName")
            default: println("default")
        }
    }
It gives the compile-time error that "Type AnyObject cannot be implicitly downcast". But if I do the following then it does work...
code:
   let sender2 = sender as NSObject
   switch sender2 { ... }
What's this about? Is there a type-safety reason why AnyObject can't be compared to an arbitrary identifier but NSObject can?



Next I tried to do the same kind of thing with my own type:
code:
class C {}
var test1 = C()
var test2 = C()

let sender = test1
switch sender {
    case test1: println("that was test1")
    case test2: println("that was test2")
    default: println("default")
}
This gives an error on both case statements that it can't find a suitable overload for ~=. What's this about? What's special about NSObject that it does allow pattern matching by identifier, but my own class "C" doesn't?

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

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

ljw1004 posted:

What's this about? Is there a type-safety reason why AnyObject can't be compared to an arbitrary identifier but NSObject can?

No; it's worth a bug, especially since this is a predictably common pattern.

ljw1004
Jan 18, 2005

rum

Ender.uNF posted:

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:

Thanks Ender.uNF! That did the trick. Although I changed it to use reference identity...
code:
@infix func == (lhs:C, rhs:C) -> Bool {return lhs === rhs}
@infix func != (lhs:C, rhs:C) -> Bool {return lhs !== rhs}

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.

ljw1004
Jan 18, 2005

rum
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

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.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Ender.uNF posted:

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

alloc and dealloc take the same argument, which is the number of objects to allocate/deallocate. It is implicitly scaled by the size of the type. The values are required to match or it's undefined behavior; you typically always know this number anyway, and it optimizes the allocator to not have to look up the size during deallocation (in the fast path).

Also, you say Unmanaged later, but you're still really talking about UnsafePointer.


This seemed generally correct. I would ask you to not mention reinterpretCast; among other reasons, it might disappear soonish.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

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

In general, labels are part of the type of a tuple. There is an implicit conversion which can strip and add tuple labels, but it cannot change tuple labels, and it cannot strip tuple labels from a labelled tuple literal. The conversion can also reorder labelled tuple elements.

The downcast should clearly not crash the compiler. It should, however, fail at runtime, and a checked downcast should produce nil.

The implicit conversions to strip and add tuple labels may seem somewhat unsound, but there are two principles at play here. If the type of this aggregate value is actually semantically important, you should be using a struct, not a tuple. Contrariwise, if the labels are just hints, being really pedantic about them would make working with such tuples onerous, which would strongly discourage people from creating hinted APIs and thereby make the feature pointless.

As an example of the second, suppose I've written a function that returns two values. I can use tuple labels here to allow my users to pull out specific values without having to remember the order in which they were returned. But if the type system enforced tuple labels strictly, my users wouldn't be able to decompose the result without writing out labels, and they'd flame me until I removed the tuple labels again.

To look at it from a different perspective, when tuple labels are just a hint, you can add them as an incremental enhancement to an API without worrying as much about breaking all of your existing users.

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.

dizzywhip
Dec 23, 2005

Why are countCharacters and enumerate global functions? It seems a little strange, I would expect strings to have a characterCount property, or maybe a countCharacters method if you want to emphasize that it's a potentially expensive operation rather than a stored value. And enumerate seems better suited to be a method on Array. Both of those are easily added via extensions, but I'm just curious why they're designed that way in the first place.

It'd also be nice if we could just do both for item in array and for (index, item) in array instead of having to call enumerate to get the index. The docs say enumerate returns a tuple for each item, which kind of makes me wonder about the performance implications for large arrays. Maybe it's not a big deal, but it seems like it would be pretty easy to just make for (index, item) syntactic sugar around a regular for loop:

code:
for var index = 0; index < array.length; ++index {
    let item = array[index]
}
Does this just come from a desire to avoid special-case handling of for-in with arrays?

Anyways, these are pretty minor issues. Even in its early, buggy state, I absolutely love working with Swift and I can't wait to see how it evolves. I'm in the process of converting a small app to Swift and it's making it really hard to switch back to projects in other languages.

I'm also curious about selectors in Swift. It seems that they only exist for the purposes of compatibility with Objective-C and Cocoa. The performSelector: methods aren't even imported into Swift at all, so there seems to be no purpose to a selector aside from interacting with Objective-C APIs. So I'm curious how something like, say, NSUndoManager would be implemented in pure Swift. Is it even possible?

Toady
Jan 12, 2009

My guess is that the frameworks will start moving away from selectors and toward blocks.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

dizzywhip posted:

It'd also be nice if we could just do both for item in array and for (index, item) in array instead of having to call enumerate to get the index. The docs say enumerate returns a tuple for each item, which kind of makes me wonder about the performance implications for large arrays.

Tuples should not add any performance costs. You may be used to a language where making a tuple requires an allocation; that's not how they work in Swift. Under the covers, Swift generally passes around tuples by passing around the individual elements separately.

dizzywhip posted:

Maybe it's not a big deal, but it seems like it would be pretty easy to just make for (index, item) syntactic sugar around a regular for loop:

But then that makes iterating over collections of tuples (like a dictionary) really weird. for (a,b) in someDictionary isn't magic syntax specific to dictionaries; Dictionary is presenting itself as a collection of tuples of keys and values, and the (a,b) is just immediately decomposing that pair.

dizzywhip posted:

I'm also curious about selectors in Swift. It seems that they only exist for the purposes of compatibility with Objective-C and Cocoa. The performSelector: methods aren't even imported into Swift at all, so there seems to be no purpose to a selector aside from interacting with Objective-C APIs. So I'm curious how something like, say, NSUndoManager would be implemented in pure Swift. Is it even possible?

Right now, no; methods have to be exported to ObjC to get this kind of dynamism from them.

dizzywhip
Dec 23, 2005

Cool, that all makes sense. I'm still wrapping my head around all this new stuff. Thanks for answering our questions, it's really awesome to be able to communicate directly with Apple engineers!

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

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Ender.uNF posted:

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

Wonder if some lucky intern will get tasked with writing a fuzzer this summer.

dizzywhip
Dec 23, 2005

So here's an interesting problem. It'd be nice to create some strongly-typed JSON serialization methods. I can get most of the way there by defining an empty protocol and extending any JSON-compatible types with it.

code:
protocol JSONCompatible {}

extension String:     JSONCompatible {}
extension Int:        JSONCompatible {}
extension Int8:       JSONCompatible {}
extension Int16:      JSONCompatible {}
extension Int32:      JSONCompatible {}
extension Int64:      JSONCompatible {}
extension UInt:       JSONCompatible {}
extension UInt8:      JSONCompatible {}
extension UInt16:     JSONCompatible {}
extension UInt32:     JSONCompatible {}
extension UInt64:     JSONCompatible {}
extension Float:      JSONCompatible {}
extension Double:     JSONCompatible {}
extension Bool:       JSONCompatible {}
extension Array:      JSONCompatible {}
extension Dictionary: JSONCompatible {}
So now you can have methods that take in or return JSONCompatible[] or Dictionary<String, JSONCompatible>. The only problem is that nested arrays and dictionaries don't have any requirements to also only contain JSONCompatible values. Is there any way to enforce that kind of requirement in this situation?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Unfortunately, no, not yet. But you could make a JSONDictionary that just has a Dictionary<String, JSONCompatible> as its only field.

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.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
So based on error messages I'm seeing, it looks like the Self type reference can only be used in protocols to refer to the eventual class that conforms to the protocol, or as the return value of a class function (similar to instancetype in Obj-C?).

I'm trying to do something like the following, and can't figure out if it's possible to express it:

code:
extension UIControl {
  typealias ControlType = Self // <-- Nope, doesn't compile

  class BlockWrapper {
    let block: (ControlType!) -> ()
    init(block: (ControlType!) -> ()) { self.block = block }
    func call(sender: ControlType!) { block(sender) }
  }

  func addBlockForControlEvents(controlEvents: UIControlEvents, block: (ControlType!) -> ()) {
    addTarget(BlockWrapper(block), action: "call:", forControlEvents: controlEvents)
  }
}
Basically, I want to ensure that the first argument of the closure has the same type as the declared type (or a superclass) of the receiver, rather than just using UIControl. (Swift has better type safety and I want to use it!) I even tried using generics, but I can't express the closure's parameter type in such a way to force compatibility with Self.

The only way I could make it work was to declare a global generic function, and then it's easy to match arguments:

code:
class BlockWrapper<T: UIControl> {
  let block: (T!) -> ()
  init(block: (T!) -> ()) { self.block = block }
  func call(sender: T!) { block(sender) }
}

func addBlockToControl<T: UIControl>(
    control: T!, forControlEvents controlEvents: UIControlEvents, block: (T!) -> ()) {
  control.addTarget(BlockWrapper(block), action: "call:", forControlEvents: controlEvents)
}

// Compiles. Good!
addBlockToControl(UIButton(), forControlEvents: .TouchUpInside) { (btn: UIButton!) in return }
// Compiles. Good!
addBlockToControl(UIButton(), forControlEvents: .TouchUpInside) { (btn: UIControl!) in return }
// Doesn't compile. Good!
addBlockToControl(UIButton(), forControlEvents: .TouchUpInside) { (btn: UITextField!) in return }

But that sucks; it should be an extension method. Is this too much of an edge case?

The best I thought I could would be to make the method generic over T:UIControl so that I can pass in closures with more specific argument types, even without guaranteed compile-time matching, but this makes the compiler segfault: :(

code:
extension UIControl {

  class BlockWrapper<T: UIControl> {
    let block: (T!) -> ()
    init(block: (T!) -> ()) { self.block = block }
    func call(sender: T!) { block(sender) }
  }

  func addBlockForControlEvents<T: UIControl>(controlEvents: UIControlEvents, block: (T!) -> ()) {
    addTarget(BlockWrapper(block), action: "call:", forControlEvents: controlEvents)
  }
}

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Flobbster posted:

So based on error messages I'm seeing, it looks like the Self type reference can only be used in protocols to refer to the eventual class that conforms to the protocol, or as the return value of a class function (similar to instancetype in Obj-C?).

Right. It is not possible to type-check a call that uses Self in a contravariant position in any interesting way. You could do whatever static checking is possible, but the callee would not get any real type safety.

Your example is actually in a covariant position, so it could work, at least as far as taking a block parameter goes. But I'm not surprised it's pushing the implemented capabilities of Self.

You could reasonably ask for the method to be accepted, but the nested class would take a level of soundness analysis that would be kindof hard to justify.

Flobbster posted:

The best I thought I could would be to make the method generic over T:UIControl so that I can pass in closures with more specific argument types, even without guaranteed compile-time matching, but this makes the compiler segfault: :(

Oops. Please file that.

Axiem
Oct 19, 2005

I want to leave my mind blank, but I'm terrified of what will happen if I do
While fiddling around recently, I realized that Swift has built-in Array and Dictionary classes, but no corresponding Set class. Is there any particular reason for the omission? Are Sets just not used often enough to justify making a Swift counterpoint to NSSet? Or have I simply missed something in the docs?


VVVVV So much for my memory. Hah. Good to know.

Axiem fucked around with this message at 18:29 on Jul 2, 2014

ultramiraculous
Nov 12, 2003

"No..."
Grimey Drawer

Axiem posted:

While fiddling around recently, I realized that Swift has built-in Array and Dictionary classes, but no corresponding Set class. Is there any particular reason for the omission? Are Sets just not used often enough to justify making a Swift counterpoint to NSSet? Or have I simply missed something in the docs?

See:

lord funk posted:

Question for rjmccall: will there be a Swift version of sets?

rjmccall posted:

Almost certainly.

Fate Accomplice
Nov 30, 2006




Is anyone going to the NSMeetup at Dropbox in SF tonight on Swift and the future of Objective-C?

http://www.meetup.com/nsmeetup/events/190270702/

If so we should meet up and say hi.

ljw1004
Jan 18, 2005

rum
I'm confused about AnyObject. What exactly is it?

The ibook says "AnyObject can represent an instance of any class type".

The online docs say "An object is AnyObject compatible if it is an instance of an Objective-C or Swift class, or if the object can be bridged to one."

I think neither is a true definition... the truth is that AnyObject is a protocol, but a special one where the user has no ability to declare conformance to this protocol; only the compiler can do that, based on "rules". I couldn't find anywhere a list of which Swift types can be bridged to Objective-C classes...?

code:
struct S { }
class C {}
enum E {case Alpha; case Beta}

var c : AnyObject = C() // works
var i : AnyObject = Int(2) // works
var str2 : AnyObject = String("world") // works

var s : AnyObject = S() // error: S doesn't conform to protocol AnyObject
var e : AnyObject = E.Alpha // error: E doesn't conform to protocol AnyObject
var str1 : AnyObject = String?.Some("hello") // error: must unwrap it
The surprising one here is "Int". I guess it can be bridged to an Objective-C class? (Which class? Why?)



If structs are implicitly bridged to Objective-C classes, do we need to start worrying about ARC for them? I tried this but failed an assert in the playground, and I don't really understand why...

code:
unowned var w : AnyObject = 2 // EXC_BREAKPOINT in swift_unknownRetainedUnowned

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

ljw1004 posted:

I'm confused about AnyObject. What exactly is it?

It's a protocol implicitly implemented by all class types. Values of certain non-class types will convert to AnyObject because they can convert to class type, generally by turning into the corresponding, bridged Objective-C type, e.g. Int to NSNumber. There's a small and pretty well-defined set of such ObjC types. The act of bridging itself does not create retain-cycle problems — you can have a retain cycle through an array, but it's a retain cycle regardless of whether the array is stored as an NSArray or a Swift Array<Whatever>, and the solution is never to hold the array itself weakly.

ljw1004
Jan 18, 2005

rum

rjmccall posted:

Values of certain non-class types will convert to AnyObject because they can convert to class type, generally by turning into the corresponding, bridged Objective-C type, e.g. Int to NSNumber.

I'm trying to understand if this conversion (following Eric Lippert's explanation) is a conversion that changes identity by constructing a new instance of the NSNumber class? or one that preserves identity?

But I'm bamboozled by the following:

code:
var x1 = NSNumber(int:2)
var y1 = NSNumber(int:3)
y1 = 2
var b1 = (x1 === y1) // false


var x2 : AnyObject = 2
var y2 : AnyObject = 3
y2 = 2
var b2 = (x2 === y2) // true
What's going on? Is the conversion to AnyObject really constructing a new instance of the NSNumber class? What rules are being used for the === operator in the two cases?

ljw1004 fucked around with this message at 17:08 on Jul 3, 2014

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
NSNumber uses tagged pointers now, so NSNumber(int:2) doesn't create an NSNumber object and referential equality on NSNumbers isn't a meaningful operation.

dizzywhip
Dec 23, 2005

Sorry to be constantly asking questions, but I'm hitting some stumbling blocks trying to implement undo in Swift.

NSUndoManager has a few issues interacting with Swift (that I've filed a bug for), which is understandable considering the way it's implemented. It only seems to work with methods that take simple constant parameters (no var/inout params and no setting of properties). So I wrote a little extension for a more flexible closure-based API.

code:
extension NSUndoManager {
    func registerUndoCallback(callback: () -> ()) {
        self.prepareWithInvocationTarget(self)._performUndoCallback(callback)
    }
    
    func _performUndoCallback(callback: () -> ()) {
        self.registerUndoCallback(callback)
        callback()
    }
}
This seems to work well so far. My problem stems from trying to create some generic methods for basic array/dictionary operations with undo support. For example:

code:
extension Array {
    mutating func appendElement(element: T, withUndoManager undoManager: NSUndoManager) {
        undoManager.registerUndoCallback { self.removeLastElementWithUndoManager(undoManager) }
        self.append(element)
    }
    
    mutating func removeLastElementWithUndoManager(undoManager: NSUndoManager) {
        let lastElement = self[self.count - 1]
        undoManager.registerUndoCallback { self.appendElement(lastElement, withUndoManager: undoManager) }
        self.removeLast()
    }
}
This doesn't work because self isn't captured by reference in the closure, so on undo it modifies a copy of the array rather than the array itself. I also tried to create functions that take the array as an inout parameter, but that had the same effect. Not sure what the rules are for capturing inout parameters, though.

The only way I can think to do this would be to create a wrapper class around an array or dictionary that would let me pass them around by reference. I'd rather avoid that though -- the safety of array/dictionary properties being passed around by value would be lost, unless the reference version is made to be a "private" property (with an underscore), and only the actual array is exposed via a computed property.

Is there a simpler solution?

Axiem
Oct 19, 2005

I want to leave my mind blank, but I'm terrified of what will happen if I do
In the Objective-C project I am working on at my day-job, when the main Application Delegate starts up, it begins loading and indexing data before it bothers with loading any View Controllers, because that loading/indexing takes a while. This was starting to impact our Unit Tests with both performance and disk issues (as I understand it; I wasn't around before the following solution).

To solve the problem, we have two application delegates; one of them is our main delegate, and the other is an application delegate for testing that loads a simple View Controller, and skips all of the hoolabaloo of our main application delegate. The way we accomplish this is that in our main.m file, we do the following:

code:
int main(int argc, char *argv[]) {
    @autoreleasepool {
        NSString *appDelegateClass = NSStringFromClass([MainAppDelegate class]);
#ifdef UNIT_TESTS
        appDelegateClass = @"UnitTestsAppDelegate";
#endif
        return UIApplicationMain(argc, argv, nil, appDelegateClass);
    }
}
We then set up the build configuration so that running the Test target defines the UNIT_TESTS preprocessor macro.

In my fun-things-at-night project, I'm playing around with Swift, and I'm wanting to do something similar, so that I'm not loading up the whole kit and kaboodle every time I run my tests.

Is there a way to accomplish this sort of thing with Swift?

There are two ideas that spring to mind:
1. Can I define an AppDelegate on a per-build-configuration basis?
2. If I must have one AppDelegate, is there a way that I can pass in a value from the build configuration to that AppDelegate, so that I can at least choose which View Controller to load?

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"

rjmccall posted:

Right. It is not possible to type-check a call that uses Self in a contravariant position in any interesting way. You could do whatever static checking is possible, but the callee would not get any real type safety.

Your example is actually in a covariant position, so it could work, at least as far as taking a block parameter goes. But I'm not surprised it's pushing the implemented capabilities of Self.

You could reasonably ask for the method to be accepted, but the nested class would take a level of soundness analysis that would be kindof hard to justify.

I was afraid you'd say that :) I was having trouble thinking of how it would be expressed in other modern languages with generics, so I had a feeling it was unlikely.

quote:

Oops. Please file that.

Filed! 17545830

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Axiem posted:

If I must have one AppDelegate, is there a way that I can pass in a value from the build configuration to that AppDelegate, so that I can at least choose which View Controller to load?
The simplest thing to do is just set an environment variable in the debug settings for your tests and check it with getenv.

Adbot
ADBOT LOVES YOU

Axiem
Oct 19, 2005

I want to leave my mind blank, but I'm terrified of what will happen if I do

Plorkyeran posted:

The simplest thing to do is just set an environment variable in the debug settings for your tests and check it with getenv.

Huh. I did not know about that. Doing a little bit of looking, it appears that NSProcessInfo.processInfo().environment["TestBundleLocation"] is already set in the default testing schema, and not set in the actual running, so I can key off of that. So much for my effortpost

  • Locked thread