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
Gul Banana
Nov 28, 2003

hey, thanks for this! swift reads like a collection of best practices enfleshed, and it will make mac+ios dev way more pleasant. instead of being a step down from the JVM, the CLR, the web etc, now it feels mostly like a step up.

my favourite features: let, enum, and real first class functions, rather than faking them with delegate or SAM types. least favourite is the array stuff, and collections in general. there doesn't seem to be anything equivalent to scala.collection or System.Linq. perhaps those things don't work so well without GC and complex monad comprehension syntax? but they are Extremely useful.

Adbot
ADBOT LOVES YOU

Gul Banana
Nov 28, 2003

speaking of which, is typealias-in-protocol semantically equivalent to a hypothetical Protocol<T>? that is, does it have any special features or restrictions that generic protocols wouldn't, if they existed?

Gul Banana
Nov 28, 2003

can you perhaps write
code:
extension CFloat {
    @conversion func __conversion() -> CGFloat {
        return CGFloat(self)
    }
}

extension CGFloat {
    @conversion func __conversion() -> CFloat {
        return CFloat(self)
    }
}

let result:CGFloat = fmaxf((offset / view.bounds.width), 0.0)
not tested, i'm at a PC. i'm also not sure if there's a way to limit the scope of extensions.. ideally this would be something you import for a specific source file or module.

Gul Banana
Nov 28, 2003

Ender.uNF posted:

Where did you find @conversion?

dumped the LLVM IR which implements the few builtin conversions.

lord funk posted:

Can you explain why it would be bad to have this project wide? If it's a valid conversion, what's the harm?

implicit conversion is a powerful feature, but it introduces unpredictability: by including a file in your project, you can change the meaning of another file, reducing the type-safety it previously had. if it becomes a documented feature of swift, i'll probably do something like put the implicits in a separate project and import that only in source files which i want to use them, making it opt-in.

the other thing i was going to mention is that this particular conversion will behave differently on 32- and 64-bit systems, but rjmccall already demonstrated an implicit-free way around that:

rjmccall posted:

code:
max(CGFloat(offset) / view.bounds.width, 0)

Gul Banana
Nov 28, 2003

rjmccall posted:

They don't lose information, they just keep it in associated types, which admittedly makes it awkward (impossible?) to talk about Sequences of specific types as types rather than as generic constraints.

is there a moral equivalent, in Swift, of this C# code?

code:
        void IncrementAll(IEnumerable<T> ts) {
            foreach (var t in ts) {
                t.x++;
            }
        }

        var collection1 = new List<T>();
        var collection2 = new HashSet<T>();
        var collection3 = new T[]{};

        //add data to the collections

        IncrementAll(collection1);
        IncrementAll(collection2);
        IncrementAll(collection3);
e.g. can i use multiple generic types which implement the same protocol, and then pass them into a function, preserving the type info necessary for that protocol to work?

Gul Banana
Nov 28, 2003

ah, i hadn't realised you could express a constraint on a type's associated type like that. covers some major use cases at least

Gul Banana
Nov 28, 2003

code:
import Foundation

class Lazy<T> {
    let _queue: dispatch_queue_t
    let _factory: () -> T
    let _read_or_reset: dispatch_semaphore_t
    var _box: T[] //XXX this should be an optional, not an array, but a compiler bug prevents it
    
    init(valueFactory: ()->T) {
        _queue = dispatch_queue_create("lazy", nil)
        _factory = valueFactory
        _read_or_reset = dispatch_semaphore_create(0)
        _box = T[]()
        
        reset()
    }
    
    func reset() {
        dispatch_async(_queue) {
            dispatch_semaphore_wait(self._read_or_reset, DISPATCH_TIME_FOREVER)
            
            self._box = T[]()
            self._box.append(self._factory())
            
            dispatch_semaphore_signal(self._read_or_reset)
        }
    }
    
    var value: T {
        dispatch_semaphore_signal(self._read_or_reset)
    
        dispatch_sync(_queue) {}
        
        dispatch_semaphore_wait(self._read_or_reset, DISPATCH_TIME_FOREVER)

        return _box[0]
    }
}
a test program:
code:
var count = 0

let msg = Lazy<String> {
    count++
    return "initialiser run \(count) times"
}

println(msg.value)
println(msg.value)

msg.reset()

println(msg.value)
println(msg.value)
i had to work around a few compiler bugs while writing this:
- classes can't have a variable size layout (some IRgen issue)
- generic types can't contain static/class variables
- dispatch_once doesn't seem to correctly infer the types of its arguments

Gul Banana
Nov 28, 2003

sadly, just resetting a flag is not thread-safe - particularly if the calculated T doesn't fit in a CASable word

Gul Banana
Nov 28, 2003

whoa, that is a caveat you might want to document - the book does not mention it

Gul Banana
Nov 28, 2003

yeah, and my Lazy<T> implementation above uses a semaphore check which does not spin if the sempahore is already signalled. after the first init it's basically Just A Branch. i don't think that's too high a cost for making avoiding a situation where *reading* an otherwise-immutable property can be unsafe, something you'd never have to worry about with unlazy values.

Gul Banana
Nov 28, 2003

https://devforums.apple.com/message/989944#989944
arrays are being given consistent semantics, i'm very happy to see this change

Gul Banana
Nov 28, 2003

man, i'm getting tired of writing
code:
            dispatch_async(queue) {
                self.player.play() //returns Bool, see 
                return
            }
when my intent is

code:
            dispatch_async(queue) {
                player.play()
            }
ironically the one expression-language feature that rjmccall did not manage to annihilate is the one which bites me. (also, the lack of cycle-collection).

Gul Banana
Nov 28, 2003

Sinestro posted:

Also, GC sucks on anything but a big computer, and still sucks even then for large applications. I'd personally rather ARC just get smarter.

Reference counting is a form of GC. It isn't necessarily lighter-weight, even; ARC isn't fast. it is low latency compared to a traditional mark and sweep collector, but has lower throughput than state of the art generational hybrids.

Latency V throughput is a good tradeoff for phones maybe! Predictable responsiveness is great. Memory leaks are less great, and you couldn't fix them just by making it smarter. It would require core language design changes - ownership tracking, maybe memory regions. Rust is attempting this, and includes a form of reference counted pointer that uses lifetime polymorphism, but so far Mozilla has found that even once you add all that complexity it isn't easy to break cycles, unless you jump straight to value semantics.

(nice to hear about the ()->T to ()->() conversion in the works!)

Gul Banana
Nov 28, 2003

it'll be interesting to see idioms develop. right now there are a lot of different ways to manage the API boundary and optionality. you could write this:

code:
class SettingsViewController: UIViewController {
    var settingsTable: SettingsTableViewController!
    
    override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
        if let id = segue?.identifier {
            switch id {
            case "embed":
                settingsTable = segue!.destinationViewController as SettingsTableViewController
            case "pop":
                settingsTable.commit()
            default:
                return
            }
        }
    }
}
or this:
code:
    func prepareForSegue2(segue: UIStoryboardSegue?, sender: AnyObject?) {
        switch segue?.identifier {
        case .Some("embed"):
            settingsTable = segue!.destinationViewController as SettingsTableViewController
        case .Some("pop"):
            settingsTable.commit()
        default:
            return
        }
    }
or even this, encoding the knowledge that segue and identifier are "always" set in my codebase:

code:
    func prepareForSegue3(segue: UIStoryboardSegue!, sender: AnyObject?) {
        switch segue.identifier! {
        case "embed":
            settingsTable = segue.destinationViewController as SettingsTableViewController
        case "pop":
            settingsTable.commit()
        default:
            return
        }
    }
right now i've got no idea which represents best practice vOv

Gul Banana
Nov 28, 2003

failable initialisers are cool. sort of. i've often lamented the inability of constructors to fail and the factory patterns this creates.

that said, it feels like they're there for "the wrong reasons" - interoperability with old two-phase-construction apis.. but hey, if they can be wrapped sufficiently for the static analysis to be reliable, that's fine.

presumably this is another nail in the coffin of exceptions on the cocoa platform.

Gul Banana
Nov 28, 2003

will rethrows be the story for GCD async?

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?

Gul Banana
Nov 28, 2003

cocoa's explicit method names were useful in a more dynamic language and time, where messaging was rarely or barely type-checked. if xcode's completion and overlays for swift have finally stabilised, the types in the function signatures will be a better guide than verbose naming ever was, and the names become redundant.

this is kind of an extreme version of the anti-comment argument - names shouldn't repeat or attempt to informally specify information which can be *verifiably* encoded as types.

Gul Banana
Nov 28, 2003

tbh going "full java"/.net is what i like about the change. i suppose reaction is going to vary by direction of entry to the language (though i was an objc programmer once in days of yore)

Gul Banana
Nov 28, 2003

tbh it's just kind of hard to take the 'catastrophe' pov seriously having spent years programming in each of cocoa, java and .net. they're directly comparable stacks - OO application development languages with large standard libraries and managed memory and so on, where you write a lot of business logic and classes with names like CustomersView or StoreNotifyingDelegate.

objective-c has always been the standout for extremely verbose method names, which made some degree of sense as it had far less type-safety and worse tooling - but this is no longer the case. Swift has a real type system and automated refactoring capabilities, and we've been able to observe for years that these things are a sufficient or superior alternative to repeating type names in method names. you're talking about falling back to Hungarian notation, for goodness' sake.. people used to make the same arguments for why that would be a clearer way to code, and they haven't proven out.

i'm not fond of the gerunds, which may just be unfamiliarity. on the jvm or clr the famous example would probably be
yourInput.TrimCharacters(Whitespace)
..but of course the real function signature is String TrimCharacters(CharacterSet trimming). there's the exact same information as was present in stringByTrimmingCharactersInCharacterSet, in a form which is enforced by the compiler and which doesnt add noise to the process of scanning code for semantic correctness and functional comprehension.

we should not be optimising for the authoring ability of beginners who aren't aware of docs or ide mechanisms. this stuff is read far more than its written, by developers who are neither novices nor experts. what's useful to them is a clear layout of the flow of well-named data between well-named operations; types are almost irrelevant. types are the thing the compiler checked, so you don't have to worry about those!

Gul Banana
Nov 28, 2003

Subjunctive posted:

In my experience of questionable success, you can optimize for beginners, for mastery, and for extensibility (it being obvious to a library author what the Swifty thing is, and to a consumer how it fits together), all largely by one principle:

Minimize exceptions.

Every time you have to say "except" or "but" in your language overview, you lose some ground. Every time some tool built to process your stuff needs a special if, an angel loses its wings.

I agree, but it doesn't sound like that principle helps us make a decision here. "Always repeat type names" and "never repeat type names" would both pass...

Gul Banana
Nov 28, 2003

"20 years behind the state of the art in academia"

Gul Banana
Nov 28, 2003

it's a very strange thing to get het up about, since unless you actually *forbid* nonvirtual methods people who care about api design will still be designing their inheritance contracts accordingly.

Gul Banana
Nov 28, 2003

man, "public open" made way more sense than the accessibility default magically changing when you un-final the type :/

Gul Banana
Nov 28, 2003

rjmccall posted:

If it's not public already, you don't need to un-final the type. Solution: don't think of open as un-final'ing the type. :)

that's reasonable. I'd forgotten about the nuanced nature of internal accessibility in swift - good to see these things being experimented with rather than just copying past systems

Gul Banana
Nov 28, 2003

using mailing lists isn't for old people, it's for people whose job regularly, rather than peripherally, involves this sort of collaboration. as soon as you are involved in the development of more than one thing, mailing lists for each is superior because it lets you have a single mail client rather than separate accounts on multiple differently-interfaced websites

Adbot
ADBOT LOVES YOU

Gul Banana
Nov 28, 2003

lord funk posted:

Model View Controller (MVC).

live from wwdc!
https://www.youtube.com/watch?v=YYvOGPMLVDo

  • Locked thread