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
Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
Having some problems with interop. The docs seem to suggest that I should import "ModuleName-Swift.h" into all the ObjC files that need to have access to Swift classes.

My module name is for sure AdultQuest because Xcode generated "AdultQuest-Bridging-Header.h" for the other side. I don't see AdultQuest-Swift.h in my project anywhere, though, and when I try to import it, I get an error complaining that it's unable to find it.

Also, when I had a protocol defined on the ObjC side which used UIKit classes, I couldn't use any classes that implemented that protocol in my Swift classes; I got compile errors about UILocalNotification being an unknown class. I converted that one to Swift and now it works fine, but now I'm stuck with this bridging issue which is much more painful.

I'm having a blast with the language so far though. Yes let's please convert two files into one that's half the length of either one.

spongeh posted:

Is there any chance at being able to use this for cross-platform dev in the future? If it outputs LLVM, and integrates with C libraries, it should be feasible once it hits open source, right? Or is too much useful stuff tied up in Cocoa that you'd lose most of the nice bits if you were trying to build on Linux or Windows.

I don't see any reason why the core language couldn't be ported. This isn't like Objective-C where really the only reason anyone would write code in it is because of Cocoa.

Adbot
ADBOT LOVES YOU

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

rjmccall posted:

It sounds like Xcode decided to name your bridging header "AdultQuest-Bridging-Header.h" for some reason. The file name isn't magical, and I assume there's a build setting for it somewhere. Basically, Swift "includes" it to find local definitions from your project that it should make visible to Swift files.

Not sure what's going on with your protocol. I know there's an occasional issue where we import protocols as FooProto instead of Foo, but IIRC that should only happen when there's an actual name conflict with an ObjC protocol (which live in a different namespace in ObjC).

There is a build setting for it, but it starts out generated from your module name. It's just how I know for sure what the module name is.

I thought maybe this could be due to some circular dependency issues, but now I'm thinking it's because the Swift part of my code isn't compiling properly.

Also, I think I have a reproducible segfault in the compiler, which I'm going to try and trim down. Unfortunately for me, it's in one of the core methods of my main model class. (Which should really be broken into pieces.)

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
Yeah, on that note. What's the easiest way to go from an NSSet to a strongly typed Swift array?

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
Okay, I've managed to get my build issues sorted out and I have converted one class in my app to Swift.

It's a simple class, just a Core Data NSManagedObject subclass with a couple of properties and a convenience initializer.

Here's the whole class:
code:
class Sphere : NSManagedObject
{
    @NSManaged var title: String
    @NSManaged var quests: NSSet
    
    class func insertWithTitle(title:String, intoContext context:NSManagedObjectContext) -> Sphere
    {
        let sphere = NSEntityDescription.insertNewObjectForEntityForName("Sphere", inManagedObjectContext:context) as Sphere
        sphere.title = title
        return sphere
    }
}
But I can't appear to cast the return value from insertNewObjectForEntityForName to this class. I assigned it to AnyObject and the type isn't quite the same name.

I can work around it for now by just creating the object outside of the class, but I kind of like being able to construct a Core Data object by just passing some parameters and the context.

Should I file a radar?

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

rjmccall posted:

Yes, please do. This is probably a matter of us getting somehow confused by the dynamic subclassing that Core Data does.

Thought as much :) rdar://17177849

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Axiem posted:

I kind of figured as such. Their steadfast opposition to ARC because ~optimization~ doesn't ring well to my ears.

That's how I felt on reading that page. Yeah, of course it's not as fast as C. It isn't that much slower than C, and you've got to trade something for those nice features.

"We like manual memory management" indeed. Fine, live in your filth then. I'll be up here in my ivory tower getting poo poo done.

And it's not like performance won't improve over time. ObjC has 20 years of optimization efforts behind it. In five years Swift is going to be a lot faster.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
I've wanted to write this code for a very long time :swoon:

code:
@infix func >= (left:NSDecimalNumber, right:NSDecimalNumber) -> Bool
{
    return left.compare(right) != NSComparisonResult.OrderedAscending
}
e: https://gist.github.com/anisoptera/5708afc32454ed868363

Dessert Rose fucked around with this message at 07:00 on Jun 6, 2014

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
Found a fun crash. Paste this into a playground:

code:
@objc
protocol Notifiable
{
    let fireDate: NSDate
}
e: opened rdar://17194123

I know you're not supposed to use let now, but I didn't when I wrote this code and then the segfault actually happened in a completely different file a good fifteen minutes of work later. Beta tools are fun :D

Dessert Rose fucked around with this message at 08:45 on Jun 6, 2014

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Vanadium posted:

Expected Results: I'm writing objc
Actual Results: I'm not writing objc? wtf is going on??

Expected Results: this is a language I already know
Actual Results: I have to learn a new thing?? gently caress you Apple!!

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
I just got the chance to really play (ha) with the Playground, building a feature in my app, and it is a dream.

The fact that it doesn't link with the rest of your project is a downside, but it's also an upside. I think if that does get added it needs to be optional. It doesn't take that much time to make mock pieces that your code actually needs to touch; we're not trying to write an entire app in here, just a small piece of code that you'll take into the main project when you're done.

Then you can visualize the progress through your algorithm with graphs. You might say, well, how is a graph of my variable actually useful? And maybe a graph isn't your first choice for representing the data, true. But we're not creating reports to show to other people, here. It is useful to be able to see the value of this variable every time we went through the for loop.

I wrote a reasonably complex (for me) algorithm this way, debugging it fluidly and quickly because I didn't have to plow through six layers of my app to test that it worked how I expected, getting instant visual feedback on the changes I was making and how they changed the behavior of my algorithm.

And when I was done, I just checked the .playground file into my repo, because next time I want to tweak that algorithm or try a different thing or write more unit tests, I already have the environment where all those mock objects are defined, all those graphs are nicely laid out.

This is really, really good.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
Are you supposed to have to annotate an NSManagedObject subclass with @objc?

I was under the impression that you didn't, but I couldn't get instance methods to work until I added it. The strange thing is that I can call class methods on another NSManagedObject subclass without it.

Which one is the bug? :)

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Doctor w-rw-rw- posted:

Did you annotate the properties as NSManaged?

Yes. Also it apparently only works if I actually specify the name of the class. @objc isn't sufficient.

I'm not sure it actually works, though, because when I try to assign to an instance variable inside the class, it crashes.

I'm about to give up on converting my model to Swift for now and just try my luck at the controller layer.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
rdar://17216333 - I should be able to include 'nil' in a switch statement over a nullable enum.

I suppose I could just add "None" as an enum case as a temporary workaround. Maybe I should stop thinking in nullable-by-default patterns.

Doctor w-rw-rw- posted:

You've posted no example code, so we can only spitball and hope we don't run into the same issue. If you could please share?

I haven't made the effort to trim it down into a good example case, because it involves having a full Core Data stack. Here are the parts that are the problem, but I have a feeling this will not actually reproduce it:

Quest.swift:

code:
@objc(Quest)
class Quest : NSManagedObject, Notifiable
{
    @NSManaged var completed: Bool

[...]

    func complete()
    {
        if (completed) { return }
        
        completed = true; // EXC_BAD_ACCESS
        
        if (resetType != .Countdown)
        {
            giveReward()
        }
        
        if (resetType != .None)
        {
            next_reset = NSDate(timeIntervalSinceNow: 0) + NSTimeInterval(reset_time)
        }
    }
}
QuestsViewController.m:
code:
- (void)longPress:(UILongPressGestureRecognizer *)gesture
{
    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        UITableViewCell *cell = (UITableViewCell *)[gesture view];
        NSIndexPath *path = [self.table_view indexPathForCell:cell];
        Quest *q = [self.fetchedResultsController objectAtIndexPath:path];
        if (!q.completed)
        {
            [q complete]; // crash!
        }
        else
        {
            [q fail];
        }
        [APP_DELEGATE updateQuestNotifications];
    }
}
Note that the ObjC equivalent Quest.m does exactly the same thing and works.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
rdar://17217571

The following code works in a playground, but segfaults the compiler in an actual iOS app:

code:
import Foundation
import UIKit

class Foo : UIViewController
{
    let foo: (Int) -> String =
    {
        let bar = "xyzzy"
        
        return {(Int) -> String in bar }
    }()
}
It has to be a closure that takes a value and returns a value, and it has to be a UIViewController subclass.

edit: This, however, does work, and is almost as awesome:

code:
    let formatter: NSNumberFormatter =
    {
        let formatter = NSNumberFormatter()
        formatter.positiveFormat = "00"
        
        return formatter
    }()

Dessert Rose fucked around with this message at 21:46 on Jun 7, 2014

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Ender.uNF posted:

error: Use of unresolved identifier 'doIt'


So the compiler isn't smart enough to resolve symbols declared in the same file unless declared in-order?

It works in classes, but maybe not at the top level, in a playground which is evaluating line-by-line.

Am I supposed to be able to modify enum values if I pattern-match them?

This:

code:
enum Foo
{
    case Bar(Int)
}

var baz = Foo.Bar(42)

func update(f: Foo)
{
    switch (f)
    {
    case var .Bar(val):
        val -= 1
    }
}

update(baz)
update(baz)
leaves baz's actual value as 42, though I'm allowed to change it within the scope of that function.

It doesn't seem very useful to be able to declare these as mutable if my changes don't affect the underlying object's values.

Dessert Rose fucked around with this message at 04:31 on Jun 8, 2014

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Plorkyeran posted:

Enums are value types, so you're passing a copy each time you call update. You have to box the enum if you want to pass a reference.

Okay, but this has the same result:

code:
enum Foo
{
    case Bar(Int)
}

var baz = Foo.Bar(42)
switch (baz)
{
case var .Bar(val):
    val -= 1
}
switch (baz)
{
case var .Bar(val):
    val -= 1
}

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
More adventures in Core Data interop:

If I pass a string to an ObjC method from Swift, and use that string as the name of a Core Data entity, it looks up the NSEntityDescription fine on the simulator, but fails on the device.

That is, the following code:

code:

let foo = Bar("Entity") as NSEntityDescription

(ObjC)
code:

+ NSEntityDescription Bar(NSString *name) {
return [NSEntityDescription entityForName:name inContext:context];
}

On the simulator, this returns an NSEntityDescription for the name. On the device, this returns nil.

I worked around it by passing the string from inside an ObjC method, but it's still some twilight zone stuff.

Edit: in the debugger, I looked: it is filling *name with something that looks to my eyes like "Entity", it even compares with an NSString constructed by the debugger properly... But it doesn't match the key in the entitiesByName dictionary in my object model.

Dessert Rose fucked around with this message at 19:45 on Jun 10, 2014

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
I keep banging my head into this Xcode bug where suddenly it will decide that my target might include its own product for every project I build. Even ones which previously built fine.

Is there at least a reliable workaround? I hit it again and I don't remember what I did to fix it last time.

If I could find a way to get out of this state I could see what was getting me into it.

ed: To be clear, I'm getting this as the entirety of my build output:

code:
Check dependencies

Unable to run command 'CompileSwift normal' - this target might include its own product.
Unable to run command 'Ditto AdultQuest-Swift.h' - this target might include its own product.
Unable to run command 'Ld AdultQuest' - this target might include its own product.
Unable to run command 'Ditto x86_64.swiftmodule' - this target might include its own product.
Unable to run command 'GenerateDSYMFile AdultQuest.app.dSYM' - this target might include its own product.
Unable to run command 'CopySwiftLibs AdultQuest.app' - this target might include its own product.
Unable to run command 'Touch AdultQuest.app' - this target might include its own product.
I get this even when I check out a known-good state that used to build fine.

edit 2: While my Simulator 5s and device targets are broken, my 5 simulator is not, and I was able to get to a buildable state. I then found several issues with Core Data that I'm firing off some radars for now.

The swift-conversion branch of my project is in a perpetually broken state. New features written in Swift work great, though!

Dessert Rose fucked around with this message at 06:26 on Jun 19, 2014

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

eschaton posted:

Do you have something like your app's Info.plist also included in a Copy Bundle Resources build phase? That's often the culprit, typically the result of clicking the "please make this a member of my target" checkbox.

No, I've checked my build phases six times. It also only affects a couple of compile targets (5s simulator and my device (a 5s, coincidentally)) so I don't know what it could be.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

PleasureKevin posted:

should this not print in the playground?

println("Hello, world")

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Choadmaster posted:

The worst roadblock was being utterly unable to use NSWindowController to load a nib, because init(windowNibName:) is a convenience initializer and thus it simply cannot be called from a subclass initializer. Praying that gets fixed soon.

You filed a bug, right? :)

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
Ugh. This doesn't work:

code:
enum QueryResult
{
    case Error(error: NSError)
    case Results(results: [NSObject])
}

let bar = QueryResult.Results(results: [])

switch(bar)
{
case .Error(let error):
    abort()
    
case .Results(let results):
    for s in results
    {
    }
}
which really puts a cramp in my Core Data querying style, let me tell you.

(You can do it if you explicitly cast "results" to an array type, but it's still frustrating.)

Also, I dislike not being able to explicitly specialize generic methods. I'd prefer "fetchObjects<Quest>(...)" to "fetchObjects(...) as QueryResult<Quest>" by far, and it would let me do stupid tricks like have the entity name in an object property.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Plorkyeran posted:

You can pass the explicit types as a regular parameter:

code:
func fetchObjects<T: IntegerLiteralConvertible>(_: T.Type) -> [T] {
    return [1,2,3]
}

println(fetchObjects(Int))
println(fetchObjects(Float))

Oh, that's clever (and fits my use case perfectly). Thanks!

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Kallikrates posted:

Something that I sometimes did in Objective-C was return or accept specific types that conform to specific protocols.
Using Generics we can do this for function parameters (I think its analogous) but how do we enforce this on the return side?

code:

- (NSObject <Foo> *)returnsSomethingThatConforms;

code:

//compiler error
func returnsSomethingThatConforms() -> (T: NSObject where U: Foo) {}
//compiler error
func returnsSomethingThatConforms() -> (NSObject, Foo) {}

Most of my googling and reading of documentation only answers the parameter side of the question. Did I find my first swift radar?

Did you try func foo() -> (Foo) {}?

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Volte posted:

Most languages with block-level variable scoping rules have that feature (i.e. C#, C++)

C# does not have that "feature". It's a compile error if the same name could refer to two different things in the same scope.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Volte posted:

It can't shadow things at control statement scope but it and every other language I've used you can shadow variables at the function scope.
code:
public class Test {
  int i;	
  public static void Main() {
    int i = 4;
    // ...     
  }
}
Sorry for being unclear about which feature I meant.

edit: I guess that's not exactly the same since you can still refer to this.x.

That works but this doesn't:

code:
public class A
{
public int i = 5;
public void M()
{
i = 3;
int i = 7;
Console.WriteLine("{0}", i);
}
}

code:
Cannot use local variable 'i' before it is declared. The declaration of the local variable hides the field 'A.i'.

(Forgive awful indentation)

There's a special case if the same name never actually refers to a different variable in the same scope. (Or I suppose you could see it as a special case if you engineer a situation where it does.) See http://ericlippert.com/2009/11/02/simple-names-are-not-so-simple/ for a good explanation of these rules in C#.

The original code, where the same name is declared multiple times as having a different type, would not compile in C# unless you used a separate name for the cast type every time inside its own scope, like using "o" for the original object and "j" for the target of your cast.

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:

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.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
What's the deal with CKRecord and subscripting from Swift?

It works in ObjC because it implements the magic setObject:forKey: method, but Swift doesn't know about that. However, when I try to define it in a Swift extension, I get a compiler error because it's trying to define the magic method for me, but it already exists.

So I'm stuck calling setObject() from my Swift code. Which makes me sad.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
I think there are two reasons I post my issues here first.

One is that I'm not even sure if what I'm writing is valid Swift in the first place, and I don't want to spend the time writing up a bug about it.

Two is that writing up a bug is going to kill my productivity for the next hour as I reduce it into a test case and put it into a project, write up the repro steps properly, etc.

Compared to "just paste some code and rjmccall will call me an idiot or tell me to file a radar", it's pretty obvious which one I'm going to do first.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

rjmccall posted:

if you can get a test case down to the point where "xcrun swift myfile.swift" produces something obviously wrong — it emits a bad diagnostic or crashes in the compiler or crashes running the program or generates meaningless output — you really don't need anything else in the radar besides the file, the command line, and a copy/paste of the bad output. I hope there isn't some weird process preventing that.

Ah, that's much better. I'd had a couple of bugs bounced because I included just a playground or not even that, and they said to submit an entire project. If the actual requirements are somewhere in the middle, then I'll submit more bugs, thanks :)

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

dupersaurus posted:

I come from the C++ tree of OOP semantics, and have been wondering why the internal access control works as it does, and not like protected. Is this the answer to the question I didn't ask?

internal works like it does because that's how internal works in every language that has the concept (e.g. C#)

The reason why it's in Swift but protected isn't is probably related to that, though. Here's the Swift blog post on the reasoning for not having protected.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Thanks for this, I missed it too.

edit: a great talk. super excited about basically everything in here.

Dessert Rose fucked around with this message at 10:56 on Jun 10, 2015

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.

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.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
That's how I find my way around the .NET API so it's not too crazy to think that something like it could happen for Swift.

I am endlessly disappointed every time I hit autocomplete in Xcode and get a page full of complete irrelevance. With no characters after foo. at all you should be showing me things that are very close to the type I'm working on, not things like "super".

I don't think the solution is to mangle names here but rather to fix Xcode's suggestions.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
The word you're looking for is "brevity".

e: slightly less pithy: the word "clarity" has a meaning. It is orthogonal to brevity. Sometimes, clarity is improved by brevity. Other times it is not.

So of course, much like "pro-life" and "pro-choice", we should take the banners of these orthogonal concepts up as though they oppose each other directly.

Dessert Rose fucked around with this message at 06:18 on Feb 4, 2016

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
Why do you think immutable structs are a bad idea?

Adbot
ADBOT LOVES YOU

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

pokeyman posted:

A struct with var properties is still immutable.

In a way, but in another way it looks mutable in usage.

Even if the struct has var properties, it would still benefit from this syntax, because right now it takes me at least two lines to make a copy of a template struct with some changes.

  • Locked thread