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
Flobbster
Feb 17, 2005

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

Suspicious Dish posted:

This seems to be a poor choice, especially since it's one of those dumb, incredible easy-to-miss mistakes that will bite people that the compiler can't catch. I'd only include one range constructor, and deprecate or remove the other syntax immediately.

You will get blog posts from people blaming Swift for subtly doing the wrong thing.

I'd love to see a language do something similar to a proper mathematical interval syntax for integral ranges. Granted, the expression (1, 5) is ambiguous as gently caress in a lot of languages, but why not do:
  • (1..5) = [2, 3, 4]
  • [1..5) = [1, 2, 3, 4]
  • (1..5] = [2, 3, 4, 5]
  • [1..5] = [1, 2, 3, 4, 5]

I'd even consider getting rid of the two that are open at the low end and just support [x..y) and [x..y], since those are probably most likely to be used, and it maps cleanly to the classical C for loop where you usually specify the strict lower bound as the initializer and the condition is either < or <= the upper bound. No idea if that would pose difficulties in the grammar, though.

Anyway, I've always enjoyed your posts, rjmccall, and I was incredibly excited to see this announcement today. Awesome work, and congrats! This has easily been the best WWDC in years.

Adbot
ADBOT LOVES YOU

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I've read through the section on two-phase initialization and I'm wondering, what is the reason for requiring that non-nullable ivars be initialized before super.init instead of merely by the end of the initializer body?

The only reason I can think of to do this is to allow for the case where a superclass calls a method that might be overridden in a subclass and thus ensure that those ivars have been set, but that usually screams fragile OO design to me. (Unless I only think that because it's what I've been used to my whole life.)

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I've been racking by brain over some difficulty getting some complex mathematical expressions to compile involving CGRects and CGFloats, and I finally managed to distill it down to this problem:

code:
let x = Double(4) * Int(5)   // Could not find an overload for '*' that accepts the supplied arguments
...so I was surprised that see that mixed arithmetic doesn't seem to be supported if the types of the expressions (in my original case, they were variables) are explicit (as opposed to writing 4.0 * 5, which works). I couldn't find anything in the book or the docs about implicit type coercion/promotion, so is this a bug or a feature of a very strong type system?

Flobbster
Feb 17, 2005

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

Ender.uNF posted:

The book calls out that Swift does not do any automatic conversion, you must explicitly do it. It's under "The Basics", "Integer and Floating-Point Conversion":

Doh. Should have searched for "conversion" instead of "coercion". Thanks for pointing that out!

Flobbster
Feb 17, 2005

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

I can't wait till we get to see more official documentation about all of the hidden goodies in the core library. I was having some difficulties understanding how to iterate over the characters (well, the UnicodeScalars) in a string backwards. My first thought was "oh, I'll just get the unicodeScalars array and loop over that backwards", but unicodeScalars doesn't return an array, it returns a UnicodeScalarView.

So I bust out "Jump to definition" to get to the "header" file and noticed that String, String.UnicodeScalarView, and a lot of collections have these "startIndex" and "endIndex" properties. In the case of Array it just returns an Int, but for String and String.UnicodeScalarView, it returns its own IndexType datatype that implements the succ() and pred() methods. It even turns out operator overloading calls succ() for ++ and pred() for -- (but only for these index types... question about that later).

Once it all set in, I realized that you have basically implemented in Swift the same iterator pattern that C++ STL uses (protocols like ForwardIndex, BidirectionalIndex, and RandomAccessIndex confirm that), and I'm so thrilled about that. From a design purity standpoint I've always thought that C++ had it exactly right and that every (mainstream) language since then has gotten it wrong when the best solution is right there. I'm glad to see the Swift team go in the right direction. There are obviously some incredible PL minds working here.

So my question: I noticed that if I write a custom class that conforms to ForwardIndex (or its subprotocols), ++ (and --, for bidirectional) automatically knows to call succ(). But if I don't conform to that protocol, ++ doesn't automatically map to succ(). That's fine, I can write

code:
@assignment @prefix func ++(inout x: Foo) -> Foo {
  x = x.succ()
  return x
}
but the thing is, I didn't see anything in the Swift definitions that explicitly defined the ++ operator for ForwardIndex. The only thing I found was these unbound generics:

code:
@assignment @postfix func ++<T>(inout x: T) -> T
@assignment func ++<T>(inout x: T) -> T
So what magic is going on here to make those protocols ++able?

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:

In the long run, either Incrementable will become public or ++ will be gated on ForwardIndex.

Thanks for the explanation! I did think it was odd that those declarations of ++ and -- would be unbound, so it makes sense that it's just not printing "private" names. That also explains why I was seeing underscore-prefixed names like _BidirectionalIndex in the REPL output that weren't being displayed here. (The fact that we even have an AST printer built-in that lets us poke around in those declarations is killer.)

My own API design pedantry would love to see Incrementable become public and have ForwardIndex be a sub-protocol of that used in the various collections just to keep the concepts distinct (all ForwardIndexes are Incrementable but not everything that is Incrementable might be a ForwardIndex). But either way, it's great to have a peek into the deep thought going into these design decisions and how it's driven you all to so finely break down the built-in types :)

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)
  }
}

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

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
It's odd that it would report it as a strong reference because datasources, delegates, and action targets are all documented to be weak references:

https://developer.apple.com/library...ataSources.html

quote:

As with delegates, data sources are objects that must be present to receive messages from the objects requesting data. The application that uses them must ensure their persistence, retaining them if necessary in memory-managed code.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
internal and private(set) are amazing proof that Swift is being written by people who actually write software and aren't just masturbating to PL theory :allears:

(Nothing wrong with masturbating to PL theory; I frequently do it myself. But it's nice to see some truly practical concepts make it into the language too.)

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
Urgh, I just upgraded to beta 4 and it made me sad: I have an app that has a couple custom keyboard extensions, written in Swift. Since both custom keyboards share a lot of common UI code, I also created a Swift framework target in the project that the other targets depend on. This framework references some Obj-C code brought in from various Cocoapods — I have a bridging header that includes those.

This all worked fine in beta 3, but now I get the following error:

code:
<unknown>:0: error: using bridging headers with framework targets is unsupported
Command /Applications/Xcode6-Beta4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift failed with exit code 1
:(

I'm surprised that it's explicitly unsupported now when it seemed to work fine before. Are there any other options that don't involve just linking the shared code statically into each of the targets?

Flobbster
Feb 17, 2005

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

Ender.uNF posted:

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?

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.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I'm writing a keyboard extension in Swift and installed the GM on my phone to try it out. I wiped DerivedData and cleaned everything just to be on the safe side, but now I can't get the extension to start at all. All I see is this in my device logs:

code:
Dyld Error Message:
  Library not loaded: @rpath/libswiftCore.dylib
  Referenced from: /private/var/mobile/Containers/Bundle/Application/D6271BED-A1A3-441B-9EA7-BEEC3A6FFB4C/MyApp.app/PlugIns/MyKeyboard.appex/MyKeyboard
  Reason: image not found
  Dyld Version: 353.5
I noticed something potentially relevant in the release notes:

quote:

Signed OS X App Extensions may emit dyld warnings and fail to launch.
Ensure that the same team ID is set for both the app extension and the containing app. (17711503)

But I've done that and still have the problem. I even get this on a brand new project with just the basic storyboard and keyboard extension generated by default. The only potential oddity I can think of is that the containing app is Obj-C (for historical reasons) and the extension is Swift.

Anyone else run into this and come up with a fix?

EDIT: Upon further inspection, it looks like it's a problem that only manifests for Obj-C container apps with Swift extensions. If I create a new Swift app with a Swift extension, it starts fine. Not sure why this stopped working (it was fine as of Xcode beta 7) or what the cleanest fix (some combination of build settings, hopefully) is.

Flobbster fucked around with this message at 06:36 on Sep 10, 2014

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
pokeyman, it looks like adding a dummy Swift class to my app container did the trick, thanks (I was too tired to try it last night). Feels hacky, but I guess no hackier than fudging the linker settings manually, and this was faster.

duck pond posted:

I'm creating a keyboard extension too (and from your previous posts I suspect we're both building a unicode character picker), but all in ObjC - and when I installed the GM mine wouldn't start either. I'm just gonna create a new project from scratch too, I think.

THE BATTLE IS ON
(good luck with yours!)

What kind of errors are you getting on your end?

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
The grammar is even provided in the book, so it's not like there was significant reverse engineering to be done -- did he just copy-and-paste it and then run yacc or ANTLR on it?

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I'm finding myself wanting to use tuples as multi-part dictionary keys from time to time because of how easy they are to construct syntactically (imagine a table mapping something like (KeyboardAppearance, ControlState) to UIColors). I hate the extra effort of defining a full struct for this *and* the hash/equality methods.

Would it be possible for the language to make a tuple type conform to Hashable/Equatable if all of the types of their elements conform to Hashable/Equatable?

Flobbster fucked around with this message at 16:05 on Nov 11, 2014

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
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?

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:

You can put an initializer in a protocol. Is this not good enough? Is there something I'm missing?

Protocol conformance isn't structural, so you do have to tell the compiler that Float and Double implement your new-fangled protocol.

That's a nice workaround, thanks! I had a mental block on protocols having initializers, I guess. (Blame years of Java interfaces.)

It seems a bit like I'm telling the compiler what it should already know, though, and leaves the client responsible for declaring this for every type it plans to use if I leave one out. It would be great if it was implicit, but then we're getting into C++ concept land, and I realize that's way more challenging to implement than just matching against the list of protocols that something implements.

To take this further, the protocol approach wouldn't work if I needed to say, for example, that T supported "func +(lhs: T, rhs: T) -> T", right? Since that's implemented in a global function, I wouldn't be able to put that in a protocol.

rjmccall posted:

Also, why is Matrix a class type?

It honestly just hadn't occurred to me; too much usage of languages where there's no meaningful distinction. :v:

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I'm loving the new features in Swift 2 so far. Great work, rjmccall and everyone else involved :)

One thing I've been needing a lot of lately is generic typealiases, usually for giving more friendly names to blocks. I would like to write something like this (contrived example):

code:
typealias Parser<T> = String -> T

func parse(s: String, p: Parser<T>) { ... }
But I end up having to write it like this:

code:
struct ParserOf<T> {
  typealias Function = String -> T

  private init() {} // Prevent instantiation outside this compilation unit
}

func parse(s: String, p: ParserOf<T>.Function) { ... }
Is this legitimate? Using structs that I never plan to initialize for namespacing purposes feels dirty.

fleshweasel posted:

edit 2: One more question. Are there any plans to add something like C# async/await keywords to make asynchronous functions easier to use?

I would love this. Given how prevalent async blocks are nowadays, having something like this built on top of GCD would be awesome. (But I imagine there might be some desire to keep language features separate from platform APIs, at least aside from the necessary ObjC specific stuff.)

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I love being able to return Self from methods on a class, it makes writing fluent interfaces that also involve inheritance beautiful. (Although now I'm wondering if I should be doing them with protocol inheritance, structs, and protocol extensions to provide the shared parts of the implementations.)

Are there plans to expand support to Self can be used as part of a larger returned type expression? I ran into a situation where I wanted to write something like func foo() -> Helper<Self>, but that's not allowed.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
If you use structs instead of classes, then you get what you want the opposite way: all methods are "const" (non-mutating) unless you specify the mutating keyword. This won't help if you're forced to use classes, though (e.g., if you're inheriting from a framework class).

Flobbster
Feb 17, 2005

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

Doctor w-rw-rw- posted:

Well, this errors with: Type 'Index' constrained to non-protocol type 'Int'

code:
extension CollectionType where Index : Int, Generator.Element: Equatable {
    func delta(otherSequence: Self) -> Delta {
        for (otherIndex, otherItem) in otherSequence.enumerate() {
            let foo = self[otherIndex]
        }

        return Delta()
    }
}

Since Int isn't a protocol (nor is it inheritable), you need to say where Index == Int here (assuming Swift 2... I think Swift 1 uses single =).

Which begs the question, what's the difference between "where X == Y" and "where X : Y" if Y is a protocol? The compiler seems to allow both.

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:

Have I explained protocol types in this thread? The distinction between them and protocols is both interesting (I think) and important; it's probably discussed in the book, if you haven't checked it out.

Can you elaborate on the distinction? I searched through the book but couldn't find anything that about "protocol types" that seemed like anything outside the normal realm of protocols that I'm already familiar with. (I may have missed it.)

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I'm working on a library that is starting to push the sane limits of what generics and protocols can do in Swift, and I'm running into some weird situations where I feel like what I'm doing is going to bite me in the rear end later.

First, I've defined a protocol FloatingPointArithmetical that just defines all the standard arithmetic operators and math functions (sin, cos, sqrt, etc), and I have Double, Float, and CGFloat all extended to conform to those. Straight forward. (It would be great if the standard library already did this in FloatingPointType!)

Then, let's say I have a struct Foo<T> that contains an array of T and some other state and methods, and I have a likewise-defined protocol with an associated type:

code:
public protocol FooProtocol {
  typealias Value
  // other stuff
}
public struct Foo<T>: FooProtocol {
  typealias Value = T
  private var bar: [T]
  private func manglePrivates() { /* ... */ }
}
I want to extend Foo with additional methods only when T conforms to FloatingPointArithmetical. The catch is, my extension methods need to be able to call the private manglePrivates method inside Foo.

My first thought was to extend the struct with a where clause (extension struct Foo where Value: FloatingPointArithmetical) but that doesn't work because you can only extend protocols with where-clauses. Fair enough, I can extend FooProtocol instead, but that would require me to lift up any private data from Foo as vars/funcs in FooProtocol so that my extension methods can see it. I don't want to expose that.

I thought, what if I created a private _FooProtocol that defined manglePrivates, and had FooProtocol inherit from that? Can't do it—a public protocol can't inherit from a less-accessible protocol.

It turns out what I can do is this:

code:
private protocol _FooProtocol {
  func manglePrivates()
}
public protocol FooProtocol { /* same as above */ }

public struct Foo<T>: FooProtocol, _FooProtocol { /* same as above */ }

public extension FooProtocol where Value: FloatingPointArithmetical, Self: _FooProtocol {
  public func myFloatingPointMethod() {
     manglePrivates()
  }
}

let x = Foo<String>()  // x doesn't have myFloatingPointMethod, which is correct
let y = Foo<Double>()
y.myFloatingPointMethod()  // also correct
:stare:

It compiles and runs, but I look at that and see two things that make me a little worried:

1. I've got a struct extending a private protocol; why is this allowed but it's not for protocol inheritance?
2. I've got that bizarre Self constraint in my extension to fake a composed protocol extension (I tried extending protocol<FooProtocol, _FooProtocol> but non-nominal types can't be extended, and I couldn't define my own named protocol that inherits from both because of the same access control issue above).

Am I going to regret this?

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:

That was fixed in Beta 2.

I'm going to hope that that works well enough for you and ignore the rest of your question. :)

That'll teach me to fall behind on my betas :) Thanks, upgrading to beta 2 did the trick and simplified my code quite a bit!

The only hang-up I ran into that had me scratching my head for a minute: my extension's constraint had to be applied to the generic type parameter name T and not to the protocol's typealias Value; trying to do the latter (a holdover from the protocol-based extension) caused the compiler to segfault. I filed rdar://21659734 for this.

Thanks for the write-up about protocols vs. protocol types. Clearly I wish my graduate PL course had been more theoretical instead of a survey of languages :v: But that definitely makes sense in the way that protocols with Self requirements can't be used as types in the context of variable decls and whatnot.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I was excited yesterday to find a situation where a particular combination of property declarations in a harmless looking generic struct compiled fine, but deadlocked at runtime when I tried initializing the struct (rdar://21664816) :v:

code:
public struct Foo<T> {
  public var thing1: T?
  public var thing2: (Foo -> Void)?
}

let foo = Foo<String>(); // nope nope nope
Will we one day be able to add stored properties to extensions, pretty please? If this was Objective-C I would just use associated objects, but I live in a Swift-only structful world whenever possible. Since I've been writing these things where certain structs have additional methods based on their associated types, there are some cases where it would be nice for them to have their own data too.

Storage and memory layout requirements aside, I guess one big blocker would be that initializers on the main struct wouldn't be able to initialize properties in an extension, so non-optional things would be broken.

Flobbster fucked around with this message at 17:17 on Jul 4, 2015

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
Makes sense—I figured there were plenty of good reasons not to allow that. Maybe I should just suck it up and make them different structs...

Meanwhile, as much as I love the way Swift deals with the strings/characters/code points relationships (only language I've used that gets it even remotely right), I was doing some text processing and trying to deal with optional carriage returns and ended up spinning my wheels way longer than I should have because of this:

code:
let s = "ab\r\nc"
Array(s.characters)                    // ["a", "b", "\r\n", "c"]
s[advance(s.startIndex, 2)]            // "\r\n"
Definitely wasn't expecting those to be coalesced! That being said, it makes me code a lot cleaner because I don't have to special case \r followed by \n :)

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I'm doing horrible things with tuples :v:

I love that you can pass a tuple like (A, B, C) into a function that expects those three parameters and it just works; this gives a lot of power. But tuples are still pretty limited right now in the kind of metaprogramming magic I can do because Swift doesn't have a clean way to do arbitrary compile-time transforms from what I can tell (e.g., take tuple types (A, B) and (C, D) and produce (A, B, C, D)). I haven't done any serious modern C++ but variadic generics would help out here, I imagine.

I can write a bunch of generic functions that take, say, a tuple (A, B) and an argument C and return (A, B, C), but I'd have to write a separate one for each tuple size (or pair of tuple sizes!). I can do this, it's just repetitive. Will we ever get primitives that might make this cleaner for tuples of arbitrary size?

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
You're getting more coy with your replies lately, which means you're either annoyed or there's something big coming :v:

I choose to believe the latter!

Flobbster
Feb 17, 2005

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

Doctor w-rw-rw- posted:

Honestly, fewer crashes and generics with fewer surprises are on the top of my list of desired improvements to Swift anyways, so that's wonderful news as far as I'm concerned! :)

Thanks for your continued work on Swift.

Agreed 100%, thanks to you and your team :) As much as I'd love to have every useful feature known to man in the language, I'd much rather have faster compiles and fewer segfaults when I try to push the language past it's breaking point with some bizarre design. (E.g., the reason I needed the tuple tricks is because I'm trying to splat an array of arbitrary runtime size into the argument list of a block. I'm a sadist. I have it working in a marginally safe way, limited only by how many of times I want to C&P the code for each possible number of arguments.)

Swift is still the most fun I've had using any programming language for a long time and it's amazing how powerful and elegant it is even a year after it launched (but tell your Xcode colleagues to fix their drat formatting :argh: ).

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I'm trying to write a wrapper around pthreads (I'm doing something sooper sekrit and I want to be ready for Swift to go open source and run on other platforms and not tie myself to Foundation or GCD :v: ), but I'm hitting a super confusing retain issue:

code:
class PeeThread {
  private var thread = pthread_t()
  private var function: () -> ()

  init(function: () -> ()) {
    self.function = function
  }

  deinit {
    print("thread deallocated")
  }

  func start() {
    // Explicit retain to ensure self doesn't go away before the thread proc starts
    var retainedSelf = Unmanaged.passRetained(self)

    // arg in this closure is an UnsafeMutablePointer<Void>
    pthread_create(&thread, nil, { arg in
      sleep(1)
      let selfPtr = UnsafeMutablePointer<Unmanaged<PeeThread>>(arg)
      let self_ = selfPtr.memory.takeRetainedValue()
      self_.function() // CRASH: self_ why are you nil here??
      return nil
    }, &retainedSelf)
  }
}

// Do this stuff in a function and don't return the thread so it get released when
// it goes out of scope
func doThreadThings() {
  let thread = PeeThread() {
    print ("foo bar")
  }
  print("starting thread")
  thread.start()
}
doThreadThings()

sleep(4) // Keep the process alive a bit
I'm using Unmanaged to explicitly retain my PeeThread object so I can make sure it stays alive until I get into the thread function, but for some reason .takeRetainedValue() is returning a nil reference (self_ is 0x0000000000000000 in the debugger). The object isn't being deallocated because the print statement in deinit is never being executed, like I would expect.

This seems like it should be pretty cut and dry manual memory management—what's going on here?

I'm also running into a compiler crash when I try to make that class generic (to have a return value from the thread closure); I filed rdar://22592331.

Flobbster
Feb 17, 2005

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

Duh, thanks. I even thought about this when I was passing "var self_ = self; ... &self_" into the function originally, but then I was like "that won't retain it, and the variable is local." Somehow when I started using Unmanaged to solve the first problem, I just lost track of the other part.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
Maybe the protocol (and the methods in it too, perhaps) need to be marked @objc?

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
Is there a way yet to constrain a generic type parameter to be a subclass of or conform to another generic type parameter?

Let's say I want to pass in two type objects to a function, the second of which extends the first. If this were Java, I would just say something like:

code:
void <T> foo(Class<T> x, Class<? extends T> y)
but trying to say something similar in Swift gives me the error "Inheritance from non-protocol, non-class type T":
code:
func foo<T, U: T>(x: T.Type, y: U.Type)
which makes sense, of course, because T could be anything: a class, a struct, a protocol, an enum... and you can't inherit from some of those.

So is there any way to say "T must be a class" or "T must be a protocol"?

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:

I don't have a compiler at hand, but I believe T : class will constrain it to be a class type. However, I'd be surprised if you could then use T as the "concrete" bound on a different parameter.

I already tried that hoping it would work since that's how you create a class-only protocol, but no such luck—the parser isn't remotely cool with it (Xcode 7.1/Swift 2.1):
code:
func foo<T: class, U>(x: T.Type, y: U.Type) {
  print("from \(x) to \(y)")
}

error: expected a type name or protocol composition restricting 'T'
func foo<T: class, U>(x: T.Type, _ y: U.Type) {
            ^
error: expected '(' in argument list of function declaration
func foo<T: class, U>(x: T.Type, _ y: U.Type) {
            ^
error: consecutive statements on a line must be separated by ';'
func foo<T: class, U>(x: T.Type, _ y: U.Type) {
...among other cascading syntax errors.

quote:

Alternatively, though, do you really need to type the second as U.Type? Class metatypes have subtyping that follows inheritance.

Assuming everything else worked like I'm intending, I'd have to type both as T.Type/U.Type or both as T/U, right? In my example above, if I wrote:

code:
func foo<T, U>(x: T.Type, y: U.Type) {...}
foo(Superclass.self, y: Subclass.self)
then T = Superclass and U = Subclass (as opposed to Superclass.Type and Subclass.Type) so I need the ".Type" to indicate that I want the argument to be the type and not an instance of the type, correct?

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
Thanks. Writing T: AnyObject does the right restriction there but trying to do U: T gives me the same "inheritance from non-protocol, non-class type 'T'" error.

It occurs to me that I would want something more general for what I'm trying to do; instead of just classes, the ideal constraint would let me express "let T be any type for which there is some other type U that can conform to or inherit from T" (so T could be a protocol or a class), and then I could write "U: T" as a subsequent type argument and the compiler would be ok with that.

Between this and some tricky tuple-unpacking, I think I'm just trying to do some C++-style metaprogramming that Swift isn't able to handle (...yet?) :v:

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
Everyone's beating me to the Swift-on-the-backend bandwagon :( cuz I have a day job and a new baby and poo poo. (https://github.com/allevato/SwiftCGI, still just tinkering, ignore the jacked up Xcode project structure I have to deal with unit tests right now)

Browsing through the Perfect source code, it's pretty disappointing though. Looks like everything's a drat class—they're just writing code but not taking full advantage of the unique design features of the language. But at least they've got a pretty web page for it!

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
Accepted proposal: Remove the ++ and -- operators :munch:

Flobbster
Feb 17, 2005

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

lord funk posted:

I need to create an UnsafeMutablePointer of either type UInt16 or UInt32 to match an MTKSubmesh's MTKIndexType. I'm having trouble with the syntax.

This doesn't work, but should show what I want:

code:
let Type = (mtkSubmesh.indexType == .UInt16) ? UInt16.self : UInt32.self
let pointerToIndexData = UnsafeMutablePointer<Type>(buffer.contents())
How would I do this?

I'm pretty sure this isn't possible for a couple reasons:

1) There's no common type that the compiler can use for the variable in line 1 that would match both UInt16.Type and UInt32.Type
2) Because of that, you can't have a runtime decision decide the compile-time type of pointerToIndexData in line 2. You're asking pointerToIndexData to be UMP<UInt16> sometimes and UMP<UInt32> other times based on stuff happening while the program is running.

Can you do something like this instead?

code:
if mtkSubmesh.indexType == .UInt16 {
  doSomething(UnsafeMutablePointer<UInt16>(buffer.contents()))
} else {
  doSomething(UnsafeMutablePointer<UInt32>(buffer.contents()))
}

func doSomething<T>(pointer: UnsafeMutablePointer<T>) {
  // ...
}
Depending on what you're doing in that function, you'll probably want to add some constraints to T so the compiler lets you use the operations you want.

Adbot
ADBOT LOVES YOU

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
I'm playing around with dead stripping and Swift since I'm working on something where I might be generating a large amount of code for a library but want the linker to be able to kill anything that the user doesn't actually call. Here's my problem: -dead_strip doesn't seem to work if things are declared public.

I created a two-file test case to whittle it down. strip.swift has two functions:
code:
func foo() { print("foo") }
func bar() { print("bar") }
and main.swift:
code:
bar()
So I would expect foo() to be stripped since it's never used. When both functions are declared internal, like above, it works: foo is nowhere to be found in the executable. But, if I declare foo and bar to be public, the linker no longer strips foo out.

Here's my swiftc invocation:
code:
swiftc -o strip -Ounchecked strip.swift main.swift -Xlinker -dead_strip
It kind of makes sense that public things wouldn't get stripped since they might be needed elsewhere in the general case, but this case is surprising since it's linking into an executable so it's not going to be linked into something else that would try to use that function. Should I expect this behavior? Is this even a Swift problem, or a limitation in the linker?

Adding -whole-module-optimization doesn't have any effect, either.

Flobbster fucked around with this message at 23:35 on Jan 11, 2016

  • Locked thread