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

Flobbster posted:

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?

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

Swift code:
protocol DefaultInitializable {
    init()
}
extension Float : DefaultInitializable {}
extension Double : DefaultInitializable {}
Protocol conformance isn't structural, so you do have to tell the compiler that Float and Double implement your new-fangled protocol.

Also, why is Matrix a class type?

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!"

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:

brap
Aug 23, 2004

Grimey Drawer
If T were Int, wouldn't you be stuck with a default value in all of your cells?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Flobbster posted:

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.

The reason this protocol doesn't already exist in the stdlib is that default-initialization means something pretty different for different types. NSObject has a no-arguments initializer; it allocates a (mostly) useless new NSObject. Does that behavior make sense for your matrix class?

In other words, that's not really a sensible semantic requirement. A better one would be to constrain on e.g. FloatingPointType, and then use that protocol's ability to create values from literals. Or to make your own protocol with a factory method requirement to create initial values.

Flobbster posted:

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.

Operators are a bit of a special case, but the short version is that yes, you can put them in protocols, and conformance lookup will just know where to find them.

lord funk
Feb 16, 2004

How would you filter a String to only have upper and lowercase letters? I'm trying to iterate through an NSCharacterSet and use stringByReplacingOccurrencesOfString:withString: to do this, but my brain is failing me.

brap
Aug 23, 2004

Grimey Drawer
That might be a situation where a regular expression would work better. Something like [a-zA-Z].
http://stackoverflow.com/questions/9661690/user-regular-expression-to-find-replace-substring-in-nsstring

It should be basically the same calls in Swift.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

lord funk posted:

How would you filter a String to only have upper and lowercase letters? I'm trying to iterate through an NSCharacterSet and use stringByReplacingOccurrencesOfString:withString: to do this, but my brain is failing me.

If you like NSScanner, you could do something like
code:
func keepLetters(s: String) -> String {
  let scanner = NSScanner(string: s)
  let letterSet = NSCharacterSet.letterCharacterSet()
  scanner.charactersToBeSkipped = letterSet.invertedSet
  var components = [String]()
  var onlyLetters: NSString?
  while scanner.scanCharactersFromSet(letterSet, intoString: &onlyLetters) {
    components.append(onlyLetters!)
  }
  return "".join(components)
}
I would not be surprised to learn that an NSRegularExpression does this faster.

lord funk
Feb 16, 2004

pokeyman posted:

If you like NSScanner, you could do something like

Thanks, that's great. It's just to clean up a textfield input, but like everything Swift I feel like I'm missing something when I rely on NSString methods / scanners / character sets, etc.

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

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

dizzywhip
Dec 23, 2005

Ender.uNF posted:

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

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

Something pretty neat that I discovered when I was having this same problem is that the compiler recognizes calls to fatalError as a valid way to exit a function or initializer without meeting its requirements. So you can fatalError in an initializer without actually initializing anything and the compiler knows what that means and won't complain.

So all of my view and view controller classes just have this:

code:
required init(coder: NSCoder) {
    fatalError("NSCoding not supported.")
}
I don't actually use NSCoding so this works well for me. You might not be able to do this if you use interface builder though, since I think that uses initWithCoder: to initialize things.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Ender.uNF posted:

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

It is a totally acceptable idiom to use implicitly-unwrapped optionals for this, but yes, the better solution is to make initWithCoder just fail with a fatal error if you don't actually rely on serialization (or pull just the right value out if you do, of course).

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

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

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

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

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

brap
Aug 23, 2004

Grimey Drawer
I'm trying to learn to work with the Sequence protocol. I have 200kb or so of JSON that I deserialize into arrays of dictionaries and then into strongly typed objects. I am wondering if I could improve startup times by implementing Sequence. I get that Sequence delays the work required to create elements until the point that element is requested. I'm wondering if afterwards, the same Sequence instance can basically be provided and restarted from the top, with all the resulting values cached from the previous round, or if I need to store them internally and provide it differently for future callers. If anyone has experience implementing Sequence, I would love to hear from you. The tutorials I have found seem to indicate that the protocol has changed since June.

edit: I'm checking out the lazy collections in Swift because it looks like that's what I actually want. I guess what's getting me about this is I just want to apply map() and filter() and so on to my lazy collection and return it as the same type. As is it seems to want me to stack MapView<FilterView<MapView<T,U>>,U>... blah blah blah, it's nasty. Am I missing something?

edit: I'm getting a poor man's laziness for now by just closing on a variable like so :I

code:
func DoWorkSometime(someData: InputType) -> (() -> ResultType) {
    var result: ResultType?

    return {
        if result == nil {
            result = doWork(on: someData)
        }
        return result!
    }
}

brap fucked around with this message at 07:28 on Dec 1, 2014

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
The lazy collections don't memoize their results; they just provide a filtered/mapped view of the underlying collection. That's useful if you want to, say, iterate over a subset of the elements of an array without actually copying out the data; adding implicit memoization to that would defeat the point.

It sounds like what you basically want is a lazy result tree. Depending on how lazy you want to be, any particular node might be a strongly-typed object, a dictionary, or even just an unparsed string. I don't see any reason why you'd need to implement Sequence for that; you should just have a way to "force" a particular parser result so that it turns into a concrete Array/Dictionary when you need it be one. To get useful memoization, so that forcing the same thing twice doesn't duplicate effort, you'll need your basic node type to at least be able to store something with reference semantics; that could be a class reference, or it could just be a captured variable like you've done there.

Whether this actually improves startup times depends on whether you're really only using a subset of the data in practice; and if you are, you'd be better off finding a way to not even read the unnecessary string data into RAM.

brap
Aug 23, 2004

Grimey Drawer
It's really more like a 1-time crunch job that takes 6 or so seconds on an iPhone 4. It is data that I need to perform really basic stuff (it's information about bus stops and routes being shown on a map). The data is in a lovely form for what I need so I am doing a fair amount of transformation. I am also choosing to get all the static data about this transit system in one go because I figure it's good to minimize the number of network requests.

I have opted with the closure I wrote above. After I get the data and deserialize the parts necessary to populate the initial view, I dispatch to a background thread and crunch the rest of it. It's caused the app to become acceptably fast in loading on the iPhone 4 and blazing fast on my 6.

Thanks for helping me understand what's going on here. I do pretty much just want memoization.

ljw1004
Jan 18, 2005

rum

fleshweasel posted:

It's really more like a 1-time crunch job that takes 6 or so seconds on an iPhone 4. It is data that I need to perform really basic stuff (it's information about bus stops and routes being shown on a map). The data is in a lovely form for what I need so I am doing a fair amount of transformation. I am also choosing to get all the static data about this transit system in one go because I figure it's good to minimize the number of network requests.

Curious why you're not doing the crunching on a companion webservice that you write?

brap
Aug 23, 2004

Grimey Drawer
Cause I'm too dumb and was depending on someone else who's taking too long to make it happen.

brap fucked around with this message at 17:43 on Dec 1, 2014

Doctor w-rw-rw-
Jun 24, 2008

fleshweasel posted:

It's really more like a 1-time crunch job that takes 6 or so seconds on an iPhone 4. It is data that I need to perform really basic stuff (it's information about bus stops and routes being shown on a map). The data is in a lovely form for what I need so I am doing a fair amount of transformation.
GVFS is actually a pretty decent and easy to read format (having written a parser for it before). And if you're not working with GFVS...start? Many transit agencies offer it.

brap
Aug 23, 2004

Grimey Drawer
I wish I was. My particular town is using a different, bad schema for live arrival times for absolutely no reason. So a lot of the info is not available in google's format.

They may have the static data. My friend was actually looking at merging this zip file they apparently provide to google with what comes out of their live feed essentially.

It's pretty bad though. The names of the routes for instance are not even the same between the two data sets for instance. You have to translate between the city API's name for the route and the name they provided to google.

At any rate I should be looking into doing this the right way which is probably not making the client do all the work at launch. Thanks guys.

brap fucked around with this message at 17:49 on Dec 1, 2014

Toady
Jan 12, 2009

In an OS X project, I have an embedded framework with a Connection class that has an embedded struct type called Settings. In my application, when I create an instance of Connection.Settings and pass it to a connection method that takes a Connection.Settings argument, I get:

code:
'Connection.Settings' is not convertible to 'Connection.Settings'
Edit: I traced the issue to a framework target that was no longer in the project. I had created a new embedded framework and copied class files from the old target to the new target. The old framework was still around despite cleaning the build.

Toady fucked around with this message at 00:46 on Dec 4, 2014

Doh004
Apr 22, 2007

Mmmmm Donuts...
Hey, could someone please clarify something in regards to using Swift code in Objective-C for me?

I have a library, "CompatibleAlertController", that I've written in Swift and it works great. I want to also use it in Objective-C, but I want to add a prefix to it because it's "How We Do Things in Objective-C". So I add the following:

code:
@objc(BPCompatibleAlertController)
public class CompatibleAlertController {
// class stuff
This should make it so that when I use the code in Objective-C, I can call it as "BPCompatibleAlertController", right?

If so, why is it that the header file that gets generated for the Swift code to Objective-C ends up looking like this:

code:
SWIFT_CLASS("BPCompatibleAlertController")
@interface CompatibleAlertController
That's the reverse of what I want!

brap
Aug 23, 2004

Grimey Drawer
It doesn't seem stable to try to make the class have different names in the two languages. Living with the prefix in swift is no big deal.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Seems like a bug to me. Have you filed it?

Doh004
Apr 22, 2007

Mmmmm Donuts...
No but I can! I always first assume that I'm doing something wrong and don't want to speak outta my rear end about something. I've never done it before but I'll do it tonight :)

fleshweasel posted:

It doesn't seem stable to try to make the class have different names in the two languages. Living with the prefix in swift is no big deal.

Oh I know, but then I got yelled at because I added the prefix to the library by some nerds.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Doh004 posted:

No but I can! I always first assume that I'm doing something wrong and don't want to speak outta my rear end about something. I've never done it before but I'll do it tonight :)

Does it work if you make it a subclass of NSObject?

It's still a bug either way, I just noticed you made a root class and wonder if that triggers something.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
So, this CloudKit thing. Sure does have a whole lot of asynchrony.

Any plans to add something similar to C# async/await? Blocks are nice but Xcode doesn't exactly write { (records: [NSObject : AnyObject]!, error: NSError!) in ... } for me. And even if it did I'd still prefer to just write a method that looks like what it's doing and doesn't have a bunch of nested blocks in it.

Also, I wasn't paying attention and a bug I had open got closed as "resolved in 6.1" but it's not fixed and the test project I submitted still doesn't build so I don't know why it got resolved in the first place. And you have to make a new bug if you let it expire...

What was the point of submitting the test project then? :argh:

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
It was probably resolved as a duplicate, and then somebody failed to check all the duplicates. Does it fail in the same way?

async/await would be cool. We have a lot of things we want to do first, though.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

rjmccall posted:

It was probably resolved as a duplicate, and then somebody failed to check all the duplicates. Does it fail in the same way?

async/await would be cool. We have a lot of things we want to do first, though.

It fails in a slightly different way. Now it complains that the "type" isn't a Generator instead of it just not being an Array.

I reopened it, anyway. I was just so excited not to have to cast my array variable from an enum switch into itself in order to iterate over it.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
This might be a stupid question, but what the hell is a "partial apply forwarder for reabstraction thunk helper"?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

pokeyman posted:

This might be a stupid question, but what the hell is a "partial apply forwarder for reabstraction thunk helper"?

Reabstraction is turning one representation of a type into another. Currently, this is only a base problem for function types, although it then extends recursively into tuples and (one day) optionals.

In a generic context, you can have a function of type T -> U. By definition, the generic context doesn't know what concrete types T and U are, but that's a problem, because it's more efficient to pass certain types in certain ways. There are generally four ways to implement this:
  • You can require full instantiation of the generic code so that T and U are always known at compile time, a la C++. We didn't want to do this.
  • You can make function values always use the optimal representation: so, if T=Int and U=Float, then this function will pass those values directly in the appropriate registers. This is murderous for generic code because you'd have to perform dynamic calling convention lowering on almost every call.
  • You can make function values always use a conservative representation: so this function would always take one indirect argument pointing to a buffer holding a T and another indirect argument into which it will initialize a U. This is murderous for non-generic code. (In a dynamically-typed language, you would do this implicitly: all values have a common boxed representation.)
  • You can allow multiple representations of the same value and convert between them when appropriate. So if you have an opaque Int->Float function, and you want to pass it to generic code as a T->U function, you have to wrap with an implementation that's actually a (Float*, Int*)->() function. This is reabstraction.

So the reabstraction thunk is the function of type (Float*, Int*)->() which just forwards to the original function, and the reabstraction thunk helper is a helper function for that which exists for bad reasons, and the partial apply forwarder is a helper function for that which exists for equally bad reasons.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Cool, that makes sense.

Are the bad reasons you mention just implementation details at the moment, or is it a consequence of the design? If you can say.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Implementation details, mostly various things about what information is available to the emitter of such-and-such function at a particular stage of compilation.

take boat
Jul 8, 2006
boat: TAKEN
Out of curiosity, why didn't you want to go down the full instantiation road? Wouldn't that allow better optimizations?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
That's precisely it: we want it to be an optimization. We do have that optimization, and right now it's not very clever and it always fully instantiates everything it sees without even trying to merge similar instantiations, so the dominant end result is rather C++-ish; but if you're totally reliant on instantiation for correctness, then you're locked out of a lot of language features which use generic code dynamically, and that sucks.

Plus, it's a lot easier to make clever decisions about merging instantiations when you instantiate retroactively instead of eagerly.

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

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

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

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

rjmccall
Sep 7, 2007

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

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

brap
Aug 23, 2004

Grimey Drawer
Are there plans for standard library mechanisms for error handling i.e. the Failable<T> enum that is often suggested?

It would be nice to move forward from error pointers.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
We're looking at that right now, actually. The thing is that it's a pretty deep language question, and it's one that we don't want to answer poorly just because we rushed to a solution, whether it's a new solution with implications we didn't think through or an old solution with proven awfulness we couldn't fix.

And the thing is, while error pointers suck, they suck at a C- level, not an F level. They also have the advantage of being ubiquitous in existing APIs, and therefore falling back on them is both easy for us and familiar to our users. So when we list out our priorities, we know that we need a better error-handling solution sooner rather than later, if for no other reason than that, past some point, our users will murder us if we suggest that big of a source-compatibility break; but we also know that a C- solution can limp along for a bit while we tackle the problems with D and F grades.

So I can't really say what our solution's going to be or when it's going to be ready, because I don't know.

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

rjmccall posted:

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

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

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

Adbot
ADBOT LOVES YOU

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

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

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

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

  • Locked thread