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
lord funk
Feb 16, 2004

Is it possible to store an array of class types? I have a group of classes that conform to a protocol which declares a static variable.

code:
protocol ThingConforming {
    static var aThing: String { get }
}

class Foo: ThingConforming {
    static var aThing: String = "FooThing"
}

class Bar: ThingConforming {
    static var aThing: String = "BarThing"
}
...
What I would like to have is an array that holds the class types themselves, so I can iterate over all the classes and check their static variable:

code:
let classes = [Foo, Bar]
for class in classes {
    //check aThing
}

Adbot
ADBOT LOVES YOU

Doh004
Apr 22, 2007

Mmmmm Donuts...
The more Swift we do, the less and less I'm willing to allow force unwraps to make it through code reviews. Is that completely misguided or is having lots of if lets what we do with Swift?

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

lord funk posted:

Is it possible to store an array of class types? I have a group of classes that conform to a protocol which declares a static variable.

code:
protocol ThingConforming {
    static var aThing: String { get }
}

class Foo: ThingConforming {
    static var aThing: String = "FooThing"
}

class Bar: ThingConforming {
    static var aThing: String = "BarThing"
}
...

What I would like to have is an array that holds the class types themselves, so I can iterate over all the classes and check their static variable:

code:
let classes = [Foo, Bar]
for class in classes {
    //check aThing
}

Does let classes = [Foo.self, Bar.self] work?

Doh004 posted:

The more Swift we do, the less and less I'm willing to allow force unwraps to make it through code reviews. Is that completely misguided or is having lots of if lets what we do with Swift?

Use them where crashing is reasonable behaviour. The file manager can't give you back your App Support path? You're hosed, crash it. You're pretty sure this array is nonempty but you can't be arsed to check? Try harder.

lord funk
Feb 16, 2004

pokeyman posted:

Does let classes = [Foo.self, Bar.self] work?

Yes! Requires Swift 2 to access the properties, but it works:

code:
let classes: [ThingConforming.Type] = [Foo.self, Bar.self]

Kallikrates
Jul 7, 2002
Pro Lurker

Doh004 posted:

The more Swift we do, the less and less I'm willing to allow force unwraps to make it through code reviews. Is that completely misguided or is having lots of if lets what we do with Swift?

Our Style guide heavily discourages any force un wrapping. The nil check needs to be a short distance from the call to the force for me to allow it. But there is no blanket "Never do it ever".
code:
// example:
func compress<T, S: SequenceType where S.Generator.Element == Optional<T>>(sequence: S) -> [T] {
    return filter(sequence, { $0 != nil }).map { $0! }
}

brap
Aug 23, 2004

Grimey Drawer
Basically what pokeyman said. There are some calls that should crash your app if they return nil. For instance, I have in my app an NSURL instance created using a string literal. The only reason its initializer should fail is I wrote a bad URL string in my source code. Instead of my app sitting there and doing nothing, it might as well crash and let the debugger break on wherever the bad optional unwrap occurred. Crashes like that definitely shouldn't make it into release versions obviously.

Once we get guard let, it will be a lot easier to eliminate most of the remaining instances of force unwraps.

Kallikrates, I suspect a lot of people will be using an extension method like that one. I implemented it like this:

code:
extension Array { //or CollectionType or whatever when Swift 2 is out
    /**
        Takes a transform that returns an optional type and
        returns an array containing only the non-nil elements.
    */
    func mapUnwrap<U>(transform: T -> U?) -> [U] {
        var result = [U]()
        
        for t in self {
            if let u = transform(t) {
                result.append(u)
            }
        }
        return result
    }
}

brap fucked around with this message at 16:42 on Jun 16, 2015

dizzywhip
Dec 23, 2005

I'm playing around with protocol extensions in Swift 2, and I'm hitting an interesting limitation. I have an inheritance hierarchy with a common base class which is a container for some values, and I'd like to replace it with a protocol.

The problem is that if I extend the protocol with implementations of its methods (some of which are mutating), then I must declare the underlying container as settable in the protocol. This forces the type that publicly conforms to that protocol to also make its underlying container publicly mutable, even though I only want external code to mutate the container using the protocol methods.

Here's a simplified example:

code:
protocol IntContainerType {
    var ints: [Int] { get set }
    mutating func addInt(int: Int)
}

extension IntContainerType {
    mutating func addInt(int: Int) {
        self.ints.append(int)
        // Do some other important stuff.
    }
}

struct IntContainer: IntContainerType {
    var ints: [Int] // Externally mutable :(
}
This seems like a fundamental constraint of how protocols work, but I'm curious if anyone has any ideas for workarounds aside from going back to a class hierarchy.

brap
Aug 23, 2004

Grimey Drawer
It makes sense your protocol would need to expose a setter on the property in order to have an extension method mutate that property. You should put your add method signature in the protocol and implement it in your types conforming to the protocol.

It feels like what you were hoping for was more like an abstract class in C#.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Maybe you should do this with composition?

Doctor w-rw-rw-
Jun 24, 2008
Am I missing something here?

Swift code:
struct Foo {
  let min : CGSize
  let max : CGSize

  // ...

  func clamp(size : CGSize) -> CGSize {
    let clampedWidth = max(min.width, min(max.width, size.width))
    // ...
  }
}
pre:
Cannot invoke 'max' with an argument list of type '(CGFloat, CGFloat)'
EDIT: Duh, name collision.
EDIT 2: I didn't want to rename the variables, so I fixed it by using Swift.min and Swift.max to refer to the global functions. Sweet.

Doctor w-rw-rw- fucked around with this message at 00:03 on Jun 18, 2015

toiletbrush
May 17, 2010
I totally love the way that Swift handles errors, but how come the 'throws' keyword comes between the parameters and return type? Its just 'myFailingFunction() throws -> Int { ... }' reads a bit like the function throws an Int...but I guess it makes sense as throwing an exception is sort of a possible return type..

dizzywhip
Dec 23, 2005

rjmccall posted:

Maybe you should do this with composition?

Yeah, I think this is probably the way to go in this case.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

toiletbrush posted:

how come the 'throws' keyword comes between the parameters and return type?

It's good for readability to be able to answer "what does this produce" in a single glance instead of having to search out two different places. You'll almost always want to know that a function can throw when you're looking for its return type.

It has to go before the arrow because the arrow isn't always there, e.g. in initializers and functions returning ().

lord funk
Feb 16, 2004

Can you access a protocol's static variable in a protocol extension method?

code:
protocol SomeProtocol {
    static var typeVar: String { get }
}

extension SomeProtocol {
    func method() {
        //how to get to type's typeVar?
    }
}

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
Just checking in to say that swift 2.0 protocols solve pretty much every complaint I had about them. Core Data is so so so much better now that I can have all my entity objects conform to a protocol which allows them to return properly typed arrays with barely any additional code per class.

Self constraints are so good.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

lord funk posted:

Can you access a protocol's static variable in a protocol extension method?

Swift code:
let string = Self.typeVar

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.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Not really; it's hard to reason about the dynamic type in arbitrary positions like that. Not impossible, but it would take some major work to do well.

shodanjr_gr
Nov 20, 2007
So I've decided to get back into Swift since I've got some time on my hands. Maybe this eluded me the first time around but is there no way to tag methods (for classes) as non-mutating to the instance's state? Basically I'm trying to understand if there exists a mechanism similar to C++'s "const".

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

shodanjr_gr
Nov 20, 2007

Flobbster posted:

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

Thanks for the reply! I was aware of that but obviously structs have other tradeoffs. It would be interesting to hear the motivation behind such a design choice (paging rjmccall).

e: "defer" is the most beautiful language feature I have ever seen in my entire life.

shodanjr_gr fucked around with this message at 08:35 on Jun 19, 2015

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Mutability tracking in reference types is a lot more complex, and it's basically a different problem.

The first thing to realize is that a const reference doesn't really say anything about the object; it's just a statement about what can be achieved through that particular reference. And it's a mostly orthogonal statement to the mutating notion for value types, because you can have either a variable or a constant holding either a const or a non-const reference. In particular, a non-mutating protocol requirement can be implemented with self-mutating class method, because the class method does not reseat the reference, because that's not how class methods work. So that's confusing.

Okay. So you have a class, and now there are two different types of reference to it. If the default reference is const, you're going to force users to add a ton of pedantic non-const annotations, because the interface to many classes is centered around mutation. If the default reference is non-const, you have a major annotation propagation problem, because people will naturally write functions to expect non-const references even if they don't need to actually mutate; this means that you'll be running into incorrect annotations every time you try to lock down in one place, so that you're either endlessly janitoring const or relying on some const_cast-like explicit hole in the tracking. None of these choices are appealing.

There are also big, awkward questions about how const/non-const references interact with stuff with protocol types, or dynamic casts, or just generics in general. And none of this actually gives you any guarantee in a non-mutating class method that you won't do something that causes a mutation through an aliasing non-const reference, so the benefits for reasoning about mutation are pretty weak.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

shodanjr_gr posted:

e: "defer" is the most beautiful language feature I have ever seen in my entire life.

Seriously. Such an elegant solution to the problem.

shodanjr_gr
Nov 20, 2007

Dessert Rose posted:

Seriously. Such an elegant solution to the problem.

Indeed! And from messing around in Playgrounds, it seems that you can have multiple of them within a scope and they get executed in sequence when you bail out. Which makes them even more awesome.



I really appreciate the very detailed response and I can understand that properly enforcing const-correctness imposes some (non-trivial) overhead to developers which leads a lot of folks to cut corners and/or not do it right. So from what I gather, the only way (currently) for the compiler to enforce non-mutation is to use structs and "eat" the value-type overhead?

brap
Aug 23, 2004

Grimey Drawer
Yeah, although I'm pretty sure copy on write makes it much less of a cost than you'd think for immutable structures.

Carthag Tuek
Oct 15, 2005

Tider skal komme,
tider skal henrulle,
slægt skal følge slægters gang



Yeah, there aren't any copies until its necessary.

e: Re this, these WWDC sessions were really good imo:

Building Better Apps with Value Types in Swift
https://developer.apple.com/videos/wwdc/2015/?id=414

Protocol-Oriented Programming in Swift
https://developer.apple.com/videos/wwdc/2015/?id=408

Gul Banana
Nov 28, 2003

will rethrows be the story for GCD async?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
rethrows as currently defined doesn't help a whole lot with async, because right now async is kindof a callback-hell situation, and it really needs a more holistic solution.

You could make a very good wrapper for dispatch_sync that actually returned a result back, though, and also used rethrows.

lord funk
Feb 16, 2004

rjmccall posted:

Swift code:
let string = Self.typeVar

I swear I tried this. =/ Maybe I just let it autocomplete to self. Ahh.

Siguy
Sep 15, 2010

10.0 10.0 10.0 10.0 10.0
I am absolutely amazed at Swift's progress as I read the new iBook and this thread. Really makes me want to make an iOS app in my spare time just to learn the intricacies.

One general question: Do any of us think (or maybe know) if Swift is ever going to bake Regular Expression literals into the main library? I know the current solution is to use NSRegularExpression or rangeOfString, but boy does that feel janky and archaic compared to other languages.

I may be an edge case, but 90% of the stuff I work on involves using regular expressions to deal with user text and convert it into something else.

brap
Aug 23, 2004

Grimey Drawer
If nothing else I would like to see the API improved. NSRegularExpression seems a little bit clunky to me.

Gul Banana
Nov 28, 2003

rjmccall posted:

rethrows as currently defined doesn't help a whole lot with async, because right now async is kindof a callback-hell situation, and it really needs a more holistic solution.

You could make a very good wrapper for dispatch_sync that actually returned a result back, though, and also used rethrows.

maybe some kind of Future-ish type which encapsulated throws-ness in the same way as rethrows, so that it became a throws operation to get the ultimate result once something in the chain was given a throws closure...
actually, is that possible as a library using overload-on-throwsness?

Doctor w-rw-rw-
Jun 24, 2008

fleshweasel posted:

If nothing else I would like to see the API improved. NSRegularExpression seems a little bit clunky to me.

Improved how? I don't expect NSRegularExpression to have all that much flexibility, since NSDataDetector derives from it and afaik it's used in a ton of text code.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Gul Banana posted:

maybe some kind of Future-ish type which encapsulated throws-ness in the same way as rethrows, so that it became a throws operation to get the ultimate result once something in the chain was given a throws closure...
actually, is that possible as a library using overload-on-throwsness?

Yes. It's just a question of API design, i.e. whether you're willing to split the future type in two. Or you could have a future that produces a Result<T>, or whatever we end up calling it.

brap
Aug 23, 2004

Grimey Drawer
Swift 1.2
1. Not sure how to create a string with an NSRange without using NSString. NSRange can't be converted easily to Swift's Range<String.Index>.
2. The option named "allZeros" throws me off until I think about the way options are often implemented with bitwise OR. I shouldn't even have to use an overload that takes options unless I need to stray from the defaults.
3. Why are there options at the time I create the regex instance and again at the time I perform a match? Do people normally write a pattern and then want to change the rules around during their parsing job?
4. Why do I have to provide an NSRange when by default it should be assumed I want to look for matches in the entire string?
code:
var errorPtr = NSErrorPointer()
if let regex = NSRegularExpression(pattern: "\\d\\d",
    options: NSRegularExpressionOptions.allZeros, error: errorPtr) {
        if (errorPtr != nil) {
            fatalError("bad regex pattern")
        }
        
        let str: NSString = "43, 22"
        
        let matches = regex.matchesInString(str as String,
            options: NSMatchingOptions.allZeros,
            range: NSMakeRange(0, str.length))
        
        for match in matches {
            if let range = match.range {
                println(str.substringWithRange(range))
            }
        }
}
JavaScript
code:
var matches = "43, 22".match(/\d\d/g);
for (var i = 0; i < matches.length; i++) {
    console.log(matches[i]);
}
I don't like JavaScript as a language for serious projects, but which one would you rather use?

Also, I am looking forward to when pressing "." in a place where an enum function parameter belongs brings up the list of cases for that enum. Otherwise I have to type out the full name of the enum type while I'm just learning to use that particular enum.

brap fucked around with this message at 21:40 on Jun 20, 2015

Doctor w-rw-rw-
Jun 24, 2008

rjmccall posted:

(snip)
right now async is kindof a callback-hell situation, and it really needs a more holistic solution.

rjmccall posted:

Yes. It's just a question of API design, i.e. whether you're willing to split the future type in two. Or you could have a future that produces a Result<T>, or whatever we end up calling it.

IMO Promise or Future style APIs are easy to abuse really, really badly. In one of my previous projects, a coworker wrote chains of promises with multiple branches which statefully changed a view controller (for example, showing/hiding the loading UI). It was a huge mess, and naturally, everything was crashy and hard to reason about. My takeaway was that without one of: a very strong convention of purity (mutating only locally within the code block), an in-language facility to help enforce purity, or a great deal of discipline, Futures and Promises seem to have a high risk of codebase devastation.

I also think that they tend to be a poor fit for implementing frequent or complex UI mutations. I wrote a channel/pipeline framework very (very) loosely resembling Netty's and an application on top of it, and came away from it feeling that overall, it's just really hard to beat just writing code sequentially. Being able to do so and also punt control to the background for long-running tasks and pick up where you left off would be really good.

That said, pausing the main thread and resuming it isn't exactly an option since UIKit requires the main thread to be continually running and minimally blocked for decent performance.

tl;dr: What would adding a async/await abstraction to the language would look like? Would it have a clearer story for exception handling? I don't pretend to know how much of a pain in the rear end that would be to implement. Maybe some way to make a continuation passing style not look awkward as hell instead?

Siguy
Sep 15, 2010

10.0 10.0 10.0 10.0 10.0

fleshweasel posted:

/big list of things unpleasant about using Regular Expressions in Cocoa/g

Yes! Exactly. Thanks for writing that out.

I can see why it might be a weird fit for the Cocoa libraries for Swift to have its own special regular expression functionality that operates differently from NSRegularExpression, but the current system feels like a ton of boilerplate weirdness just to accomplish simple tasks.

Even having to write out regular expressions with double slashes (e.g. writing \d as \\d so NSString doesn't freak out) stands my hair on end. RegExes are ugly enough without extra slashes.

The transition to Swift seems like an excellent opportunity to simplify things.

Doctor w-rw-rw-
Jun 24, 2008
IMO, a literal for raw strings (like with Python) that uses different escaping rules would be preferable to integrated regex functionality.

chaosbreather
Dec 9, 2001

Wry and wise,
but also very sexual.

After watching the great Protocol-Oriented Programming WWDC Swift talk and doing my first mediumly-complex iOS app with Swift 2, it's hard not be struck by how foreign the standard Cocoa/UIKit OO delegate/subclass OO stuff feels. It really makes me wonder what a completely Swift API development stack would be like. Pretty great, I bet.

Adbot
ADBOT LOVES YOU

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

rjmccall posted:

Result<T>, or whatever we end up calling it.

Burrito<T>

  • Locked thread