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

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

Adbot
ADBOT LOVES YOU

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
Swift won't automatically coerce function types? That's a drag IMHO... A function returning bool should satisfy the contract of a function returning void (discard the bool).

I've also found myself having to give the parameter types for closures in situations where it seems like the compiler should be able to infer it.


Also we agree about the cycles; the one big ugly wart on ARC. I still wonder if it wouldn't be possible to detect the extremely common cases and make self weak automatically.


rjmccall: is there anything about Swift that would preclude garbage collection? Obviously the current runtime and compiler are centered around ARC, but it seemed like you could in theory have a runtime and compiler that was GC'd. Leaving the ObjC interop aside of course.

Sinestro
Oct 31, 2010

The perfect day needs the perfect set of wheels.
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.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
We should be able to do that particular closure coercion, and it think we're even tracking it; just fighting bigger fires right now.

Nothing about the core language precludes being implemented with GC.

Vanadium
Jan 8, 2005

Gul Banana posted:

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

Haha, that's what you get for everybody complaining about rust's TOTALLY ABSTRUSE semicolon semantics~

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

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

rjmccall posted:

The second is intimately related. Whether or not a tail call is used is sometimes very important. Typically, when something is very important, it's good to let the code be more explicit about it. So I could imagine adding an explicit "use a tail-call here, please" annotation, and we would guarantee to either honor it or report failure (e.g. if it's not actually in a tail position, or if the implementation model cannot possibly support a tail call there). However, that would not lead to particularly attractive functional-style recursive code.

Does it really have to be unattractive? With something like call <expr> instead of return <expr>, you could make it explicit and checkable without making it more clumsy, I think.

But then the question arises of "what do you do when you get that error?" Make it iterative? Would be pretty brutal to have some existing and complex tail-calling code that suddenly isn't tail callable, meaning you have to undertake a major refactoring. It's not like you can change the refcounting mode, and if it's dependent on compiler optimizations being able to elide reference operations then you better never be able to turn that optimization off, or your code won't compile.

rjmccall posted:

The last is that I, personally, am not even slightly interested in promoting deeply-recursive programming, because it almost certainly means that you're using some sort of terrible data structure, like a singly-linked list or a binary search tree, just because it has a nice recursive form. (And yes, I am aware that there are occasional uses for both, as well as that immutable data structures have a number of nice concurrency advantages.)

I'm surprised to hear an objection to things like recursively-manipulated binary search trees; what would you recommend that people use for those use cases instead? (And how will people ever do CS 101 interview questions in Swift? :ohdear:)

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Subjunctive posted:

Does it really have to be unattractive? With something like call <expr> instead of return <expr>, you could make it explicit and checkable without making it more clumsy, I think.

I'm not saying it'd necessarily be syntactically unattractive, I'm saying that it'd become this subtle gotcha for people writing recursive code and everyone would hate it. Functional languages work because tail calls are guaranteed for calls in tail position; if you had to opt into them, the recursion-heavy style encouraged by those languages would suck.

Subjunctive posted:

But then the question arises of "what do you do when you get that error?" Make it iterative? Would be pretty brutal to have some existing and complex tail-calling code that suddenly isn't tail callable, meaning you have to undertake a major refactoring.

My experience has been that a lot of functional tail recursion tends to involve a pretty small function doing what's effectively local mutation via argument-passing, e.g.

code:

fun whatever f g lst =
  let fun helper (h::t) s v i = helper t (f s h) (g v i) (i + 1)
          helper nil s v i = (s,v)
  in helper lst "" 0 0

Complex combinators tail-recursing to each other are terrible code no matter how you slice it, and a major refactoring is probably in order.

Subjunctive posted:

I'm surprised to hear an objection to things like recursively-manipulated binary search trees; what would you recommend that people use for those use cases instead? (And how will people ever do CS 101 interview questions in Swift? :ohdear:)

I'm not telling you to not use recursion at all (although note that Swift does not currently directly support recursive enums; it's on the list). Swift should be able to produce tail-recursion as an optimization in the same kinds of cases that a C compiler can, and I do think that an explicit "no seriously this has to be a tail call" marker would be useful. I'm just saying that we're not going to guarantee it by default, and if you have an algorithm that relies on tail recursion, in the absence of a explicit marker, you should rewrite that algorithm to be internally iterative (which is not actually even slightly difficult when the code is already in tail-recursive form).

dizzywhip
Dec 23, 2005

This is a bug, right?

code:
extension NSRect {
    init(width: CGFloat, height: CGFloat) {
        self.init(x: 0.0, y: 0.0, width: width, height: height) // Error: Use of 'self' in delegating initializer before self.init is called
    }
}
Just wanna make sure I'm not just overlooking something dumb before I report it.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Yes, and it's actually already fixed in internal builds, so just this once you're allowed to skip filing it. :)

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

rjmccall posted:

I'm just saying that we're not going to guarantee it by default, and if you have an algorithm that relies on tail recursion, in the absence of a explicit marker, you should rewrite that algorithm to be internally iterative (which is not actually even slightly difficult when the code is already in tail-recursive form).

But sufficiently difficult that the compiler can't do it for me, I suppose!

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
It's not that this is difficult to do automatically. It's a very simple transformation when you have direct tail recursion; roughly, you make all the parameters mutable, wrap the function body in a while true loop, and turn all the tail-recursive calls into assignments to the parameters followed by continue.

However, it's a better language design to require the program to state explicitly that it's relying on a tail call:

  • If the tail call is important, you should communicate that to people reading the code. A later maintainer might otherwise naively change the function in a way that breaks the tail call.
  • If the tail call is important, you should communicate that to the compiler. The work to achieve a tail call might not be difficult, but it's not work we want to promise to do in all build modes; and yet it's presumably not acceptable for debug builds to blow out the stack.
  • A lot of things can break a tail call. Some are obvious, like just doing extra work after the call so that it's no longer in tail position. Some are less obvious, like putting the return within a guarded scope like Java's try/catch or C#'s using. Some are implicit, like interactions between calling conventions (which notably includes the code necessary to handle Objective-C autoreleased results). It's good for the compiler to be able to check that the tail call is actually possible.

Axiem
Oct 19, 2005

I want to leave my mind blank, but I'm terrified of what will happen if I do
This might be my lack of functional programming background speaking here, but what's the big deal with tail recursion? And why would I as a programmer even care whether or not the language is doing it--isn't it something under the hood anyway?

Scaevolus
Apr 16, 2007

Axiem posted:

This might be my lack of functional programming background speaking here, but what's the big deal with tail recursion? And why would I as a programmer even care whether or not the language is doing it--isn't it something under the hood anyway?

Some algorithms are naturally expressed as recursive functions. Writing recursive functions without a language promise that they'll be turned into tail calls (jump instead of call) is a quick way to overflow your stack.

Axiem
Oct 19, 2005

I want to leave my mind blank, but I'm terrified of what will happen if I do

Scaevolus posted:

Some algorithms are naturally expressed as recursive functions. Writing recursive functions without a language promise that they'll be turned into tail calls (jump instead of call) is a quick way to overflow your stack.

The only times I've caused a stack overflow when doing recursion is when I had a problem with the algorithm. I guess I just either haven't been using large enough data sets with it, or because I tend to shy away from recursion (because it is so easy to screw up on accident during code maintenance) I just haven't encountered a situation where it would cause a problem. If you're dealing with a situation where the recursion is complex enough that it causes a stack overflow, why not write it to use a loop instead?

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Swift seems so relentlessly practical, I imagine tail call optimization gets a big "who cares" stamp and goes to the back of the line.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
I'm waiting for a test run to finish, so I might as well wade into TCO details.

There are really two distinct forms of tail-call optimization. (Calling them "optimizations" is really a misnomer: they're transformations. Sometimes, transformations are just used as optional optimizations. Other times, they are used to provide higher-level guarantees; tail-call transformations are used by languages which guarantee that tail-recursion will use constant space. But "TCO" is the most common term, so "TCO" it shall be.)

Both TCOs have the same two preconditions: (1) the caller cannot have any work to do that must be performed after the call and (2) the callee cannot depend on the caller's frame still existing. For example, exception handling in the caller will always violate one of the preconditions, but which one depends on the EH implementation. In a non-zero-cost implementation, it's (1), because the caller has to unregister the handler before it returns. In a zero-cost implementation, it's (2), because when the unwinder walks up the stack it needs to see a return address belonging to the caller in order to find the handlers there. The other major source of condition (2) violations is in C-family languages where you can take the address of an object on the stack; even if you don't pass a local address directly to the tail call, the compiler has to prove that it can't access any locals that might have "escaped". For example, if you passed the address of a local variable to an earlier call, the compiler may have to assume that that function might have stashed the address somewhere where the final call can find it. Swift does lock down on things like that, though; addresses on the stack are not allowed to escape. (We implement variable capture by allocating captured variables on the heap.)

Anyway. The first form of TCO is a high-level transformation where you turn a function with a tail-recursive call to itself into a loop. This is an excellent direct optimization, in that it eliminates a lot of unnecessary entry/exit overhead. More importantly, though, it's a really powerful enabling optimization, because now the optimizer can exercise its full library of loop transformations. The other huge benefit of this optimization is that it requires zero support from the code generator. The principal drawback is that only applies to direct tail-recursion; moreover, it's quite difficult to generalize to mutually-recursive functions. Thus, this is not good enough for functional languages.

The second form of TCO is a low-level transformation that turns call instructions into jumps by destroying the current stack frame before making the call. Not all calling conventions support arbitrary tail calls: specifically, in a caller-pop convention, you cannot turn a call into a tail call if it requires more stack argument space than the current function. Therefore, it is fairly common for functional languages to use a callee-pop convention, which lets you can apply this form of TCO to any call, direct or indirect, that satisfies conditions (1) and (2); an alternative is to use a convention which passes things on the heap instead. Of course, doing this kind of low-level transformation requires support from the code generator, and LLVM's has historically been quite limited because the community focuses more on C-like languages in which TCO is just an optimization, not a semantic guarantee; the people doing functional languages generally need their own calling conventions for other reasons anyway, and so they've associated the guarantees with their specific CCs rather than trying to enable them for the standard conventions.

Toady
Jan 12, 2009

There outta be a Swift blog.

tef
May 30, 2004

-> some l-system crap ->

Axiem posted:

This might be my lack of functional programming background speaking here, but what's the big deal with tail recursion? And why would I as a programmer even care whether or not the language is doing it--isn't it something under the hood anyway?

as others have said, sometimes it's easier to implement things recursively. one case in particular stands out: state machines. one function for each state, call the function to change to that state. when you have tail call elimination, your stack won't grow as you change states. there are other ways to simulate this though, and i usually end up with a trampoline functions instead.

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

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

FWIW GHC has a totally bizarre calling convention designed around the STG, the papers on which everyone should read if they're implemented a functional language


LLVM doesn't support register pinning either which is among the reasons why the llvm backend has not taken over.

Malcolm XML fucked around with this message at 16:14 on Jun 22, 2014

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

Nipplebox posted:

There outta be a Swift blog.

My understanding is that Chris Lattner has been pushing for some policy exceptions / changes to allow the team to have a more open development process around Swift. No word on if or when that might happen.


On an unrelated note, while trying to figure out what exactly IndexType is (an associated type on Collection apparently?) and the different ones that are defined (like ForwardIndex, BidirectionalIndex, ReverseIndex, Bit (no index suffix), RandomAccessIndex) I figured hey, maybe I can grab IndexType's mirror and go spelunking to discover derived types, etc instead of having to manually trace it through the generated header. Pro tip: right-click any Swift built-in, Jump to definition and behold all the standard Swift types and functions; some of the comments are pure gold both educationally and a few humorously. Anyway since it turns out to just be a protocol associated type this wouldn't be useful since it isn't constrained to be any specific type.

I did discover ExistentialMetatype which is an awesome name. Unfortunately it turns out Mirror is fairly useless; you can't do any significant runtime introspection that I can tell, even working with a basic type like String (for example, get a list of properties or methods).


My own baseless hypothesis is that runtime introspection of type information is just not a design goal for Swift. People who expect to be able to swizzle method implementations or instantiate instances of classes by name at runtime will be disappointed, at least for now.


I also found some fun REPL bugs:

rdar://17411270 Swift REPL: eternal loop (must kill task)
code:
users-mac:~ user$ xcrun swift
Welcome to Swift!  Type :help for assistance.
  1> var arr = [1,2,3,4]
arr: Int[] = size=4 {
  [0] = 1
  [1] = 2
  [2] = 3
  [3] = 4
}
  2> var m = arr.getMirror()
^Z
[2]+  Stopped                 xcrun swift
users-mac:~ user$
rdar://17411284 Swift REPL: assertion failure on isLegalSILType
code:
users-mac:~ user$ xcrun swift
Welcome to Swift!  Type :help for assistance.
  1> var s = "my string"; var m = s.getMirror()
s: String = "my string"
m: _LeafMirror<String> = {
  _value = "my string"
  summaryFunction =
  quickLookFunction =
}
  2> m.valueType
Assertion failed: (ty->isLegalSILType() && "constructing SILType with type that should have been " 
"eliminated by SIL lowering"), function SILType, file 
/SourceCache/lldb_KLONDIKE/lldb_KLONDIKE-320.3.103/llvm/tools/swift/include/swift/SIL/SILType.h, line 73.
Abort trap: 6
users-mac:~ user$ 
I've pretty much stopped trying to use the REPL or Playgrounds, almost everything I try to write crashes them.

Simulated fucked around with this message at 17:28 on Jun 22, 2014

Toady
Jan 12, 2009

Ender.uNF posted:

My understanding is that Chris Lattner has been pushing for some policy exceptions / changes to allow the team to have a more open development process around Swift. No word on if or when that might happen.

It would be nice to have in one place all the informative technical posts that are usually scattered across forums and blogs. Something in the vein of the Webkit blog.

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?

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

Flobbster posted:

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?

I believe (but don't quote me on this) that this may be a case of a built-in that just isn't represented in those public headers.



Unrelated: Swift supports doc comments to generate .swiftdoc files.

code:
///reads a line from standard input
///
///@param max:Int
/// specifies the number of bytes to read, must be at least 1 to account for null terminator.
///
///
///@return
/// the string, or nil if an error was encountered trying to read Stdin
func readln(max:Int = 8192) -> String? {
 ...
}
(my next blog post will be readln and possibly some other console input functions)

dukerson
Dec 28, 2012
Sorry if this has already been mentioned, but are there known bugs revolving around extensions? I have a pretty trivial UIFont extension that appears to be picked up in XCode but causes a compile-time segfault:

code:
extension UIColor {
    
    class func UIColorFromRGB(rgbValue: UInt) -> UIColor {
        return UIColor(
            red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
            green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
            blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
            alpha: CGFloat(1.0)
        )
    }
    
    class func backgroundColor() -> UIColor {
        return UIColorFromRGB(0xEFEFEF)
    }
}
I'm also having issues with getting the extensions actually picked up during compilation, as I've had cases with a separate file where it again gets picked up in the IDE but not during compilation (though copy-pasting it into the file using the extended funcs solves that problem.)

Awesome job on Swift -- I'm really enjoying playing with it so far. Feels like a marked improvement over ObjectiveC.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Ender.uNF posted:

I believe (but don't quote me on this) that this may be a case of a built-in that just isn't represented in those public headers.

It's not actually an unbound generic; there's just a bug in the AST printer related to hiding private declarations. Basically, all of the library protocols are very finely subdivided, I believe to work around compiler problems that may or may not now be fixed. (One of many reasons we're not guaranteeing compatibility yet.)

It's actually implemented as:

Swift code:
@prefix @assignment @transparent
func ++ <T : _Incrementable> (inout x: T) -> T {
  x = x.succ()
  return x
}
where _Incrementable is a ("private" for some reason?) super-protocol of ForwardIndex that defines succ:

Swift code:
protocol _Incrementable : Equatable {
  func succ() -> Self
}
In the long run, either Incrementable will become public or ++ will be gated on ForwardIndex.

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

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Ender.uNF posted:

I did discover ExistentialMetatype which is an awesome name.

Thanks. :) They have some major limitations right now, but it's in my queue for 1.0 to fix that.

Ender.uNF posted:

Unfortunately it turns out Mirror is fairly useless; you can't do any significant runtime introspection that I can tell, even working with a basic type like String (for example, get a list of properties or methods).

We actually have a lot of the information you'd need for things like this reflected at runtime; we just don't have an API to take advantage of it yet. Figuring out the right API there will take some real attention.

Ender.uNF posted:

My own baseless hypothesis is that runtime introspection of type information is just not a design goal for Swift. People who expect to be able to swizzle method implementations or instantiate instances of classes by name at runtime will be disappointed, at least for now.

Dynamic code modification is an awesomely expressive language feature which, by design, completely fucks over the compiler's ability to do any sort of interesting analysis and optimization. It's also much more powerful when you have a JIT. In my opinion, it'd be much better to provide a true macro language, where you can write code to manipulate the AST directly, but it's all resolved statically. That has some obvious limitations, but it also has a number of obvious performance and language-integration benefits.

Being able to use declarations reflectively is a different story and one which we'd like to support.

Ender.uNF posted:

I've pretty much stopped trying to use the REPL or Playgrounds, almost everything I try to write crashes them.

Sigh. Sorry.

rjmccall fucked around with this message at 22:36 on Jun 22, 2014

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

rjmccall posted:

Thanks. :) They have some major limitations right now, but it's in my queue for 1.0 to fix that.

We actually have a lot of the information you'd need for things like this reflected at runtime; we just don't have an API to take advantage of it yet. Figuring out the right API there will take some real attention.

That's great news; better to take the time to get the API "right", we'll all be living with it for some time.

I was just trying to use it to pry open the guts of ExistentialMetatype so not a big deal.


quote:

Sigh. Sorry.

Not a big deal; I can file bugs against some of these things, I haven't been keeping track of them so far. I've also run into a ton of cases where some partial syntax causes a crash, but someone did a good job of XPC isolation (when not in a Playground) and Xcode just gives me the popover "SourceKit Terminated - some editor functionality may be limited", then it kicks back on and I go on my merry way. I think a bunch of this is Xcode failing to handle certain kinds of Swift compiler failures.

ex: typing "withUnsafePointer" in the middle of an existing method can crash SourceKit 100% reliably for me. I only have this one because I was just using it recently, before I realized array already has withUnsafePointerToElements:
(edit) rdar://17413213 filed for this one

code:
@objc class StorageProperty<T: AnyObject>   {
    let objkey : CConstVoidPointer = "temp".cStringUsingEncoding(NSUTF8StringEncoding)! //make guid
    
    init(value: T) {
        withUnsafePointer(
        objc_setAssociatedObject(self, objkey, value, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC));
    }
}
Also you can see the horrible things I am trying to do; I'm currently trying to do a memoized version of SequenceOf<T> so I can support count(), multiple iteration, etc safely but that requires having a place to stash the concrete sequence.

Also the header for the associated object stuff typedefs objc_AssociationPolicy to uint, but the enums to int so it requires a hilarious cast. I guess that's a long-standing :confused:

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
Debugger busted! Pay no attention to the code here, I'm almost certain it won't work, I just wanted to try it. However I can't debug anything when this extension to Dictionary is present. rdar://17414370

code:
let k = "mutableProp"
let mutablePropKey : CConstVoidPointer = k.cStringUsingEncoding(NSUTF8StringEncoding)!
extension Dictionary {
    var mutableProp : String? {
    get {
        let r : AnyObject! = objc_getAssociatedObject(self, mutablePropKey)
        return r as? String
    }
    set {
        objc_setAssociatedObject(self, mutablePropKey, newValue, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC));
    }
    }
}
Set a breakpoint in the mutableProp setter and try "po k":
pre:
(lldb) po k
error: <REPL>:1:1: error: non-nominal type '$__lldb_context' cannot be extended
extension $__lldb_context {                            
^
<REPL>:9:49: error: type '@lvalue Dictionary<String, Int>' of variable is not materializable
func $__lldb_expr($__lldb_arg : COpaquePointer) {      
                                                ^
edit: This is a good one. Put these lines in main.swift instead to test if it would still happen in a different context:
code:
let kk = "mutableProp"
let mk : CConstVoidPointer = k.cStringUsingEncoding(NSUTF8StringEncoding)!
Xcode pegging CPU, debugserver pegging CPU, Xcode won't stop the task, and you can't do anything. Force-quitting the binary or debugserver don't help. Trying to quit Xcode and it prompts to stop tasks but that blocks and it is still stuck. Required full-on force quit. Fun!


edit2: :v: same thing after relaunching so apparently I have a reproducible test case.

Simulated fucked around with this message at 05:36 on Jun 23, 2014

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
We're back!

I filed a couple more Swift compiler crash bugs in the mean time.

I also discuss making Tuples Equatable

And call-by-name in Swift

Discovered you can create your own SwiftDoc with /// code comments


And here is my SwiftNonStandardLibrary, featuring the missing readln(), extensions to SequenceOf<T>, exception handling, and some other goodies. Please contribute if you can! I am accepting pull requests. A compiler bug currently prevents the tests from working properly, but if you pull the files into a console project all the tests pass.

I'm also working on a futures/GCD wrapper but haven't got anything committed yet. I don't much care for some of the others I've seen - they are fairly obvious grafts of other APIs onto Swift. I want to do something fancier, but we shall see.

eschaton
Mar 7, 2007

Don't you just hate when you wind up in a store with people who are in a socioeconomic class that is pretty obviously about two levels lower than your own?

Ender.uNF posted:

And here is my SwiftNonStandardLibrary, featuring the missing readln(), extensions to SequenceOf<T>, exception handling, and some other goodies.

Where's the code?

Doctor w-rw-rw-
Jun 24, 2008

Psst: your submodule isn't specified!

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

Doctor w-rw-rw- posted:

Psst: your submodule isn't specified!


Arrrggggg.... That's what I get for checking the "create git repo" checkbox in Xcode. It should be cleaned up now.

I'm new to the whole "Swift framework" thing so I'm sure I have screwed up something else somewhere.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice
Added ThreadLocalSlot<T> to support thread-local storage. Tests seem to be OK but don't rely on it for production code :v:

Next priorities for heavy-lifting: decent GCD abstraction and/or futures, then apply that to sequences to give seq.parallel() which will yield a sequence that automagically does its work in parallel on background queues. For light weight, some of the easier methods just need to be filled in (possibly using existing Swift library methods).



Also filed my next Swift hard crash bug report*, but that's nothing compared to SourceKit. I can't even file them all because it's too much work to figure out every individual thing that triggers the blow ups, but this one caught my eye:

Thread 5 Crashed:: Dispatch queue: sourcekit.swift.ConsumeAST
0 libsystem_c.dylib 0x00007fff8f395732 strlen + 18
1 com.apple.SourceKitService 0x000000010e482090 swift::ClangImporter::lookupValue(swift::Identifier, swift::VisibleDeclConsumer&) + 64

Crash in strlen... that looks "dangerous".

* You can't define struct init() methods with parameter default values, at least it reliably crashes for me.


edit: Manual Retain/Release in Swift

Simulated fucked around with this message at 05:20 on Jun 27, 2014

Doctor w-rw-rw-
Jun 24, 2008

Ender.uNF posted:

Added ThreadLocalSlot<T> to support thread-local storage. Tests seem to be OK but don't rely on it for production code :v:

Thread-locals are bad on modern iOS/OS X platforms in any case, IMO. With increasing use of GCD queues, and no guarantee that a queue will schedule on a consistent thread, thread-local storage isn't that useful. IMO, a wrapper for dispatch_queue_set_specific would be more useful instead.

Also, if you don't mind the Objective-C baggage, you can just use +[NSThread threadDictionary] for thread-locals (not queue-locals), anyhow. Probably not an option if you're not dealing with non-NSObject subclasses.

Ender.uNF posted:

Next priorities for heavy-lifting: decent GCD abstraction and/or futures, then apply that to sequences to give seq.parallel() which will yield a sequence that automagically does its work in parallel on background queues. For light weight, some of the easier methods just need to be filled in (possibly using existing Swift library methods).

Re: parallel collection enumeration - perhaps a wrapper around a dispatch_apply onto a concurrent queue would do nicely.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Doctor w-rw-rw- posted:

Thread-locals are bad on modern iOS/OS X platforms in any case, IMO. With increasing use of GCD queues, and no guarantee that a queue will schedule on a consistent thread, thread-local storage isn't that useful. IMO, a wrapper for dispatch_queue_set_specific would be more useful instead.

They're still pretty useful for improving parallelism by giving each thread its own resources, as with an allocator's pools or a script engine context. Precisely because you can't predict which work item will go to which thread, it's hard to apportion them appropriately at dispatch time.

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

Doctor w-rw-rw- posted:

Thread-locals are bad on modern iOS/OS X platforms in any case, IMO. With increasing use of GCD queues, and no guarantee that a queue will schedule on a consistent thread, thread-local storage isn't that useful. IMO, a wrapper for dispatch_queue_set_specific would be more useful instead.

Also, if you don't mind the Objective-C baggage, you can just use +[NSThread threadDictionary] for thread-locals (not queue-locals), anyhow. Probably not an option if you're not dealing with non-NSObject subclasses.


Re: parallel collection enumeration - perhaps a wrapper around a dispatch_apply onto a concurrent queue would do nicely.

I'm working on queue stuff right now, still in progress.

Adbot
ADBOT LOVES YOU

ljw1004
Jan 18, 2005

rum
Do these have any different behavior? The first two are immutable, but that's all I can see...

code:
var names0 = [1,2,3, "fred"]
var names1 : NSArray = [1,2,3, "fred"]
var names2 : Any[] = [1,2,3, "fred"]
var names3 : AnyObject[] = [1,2,3, "fred"]
I wonder why the inferred type of "names0" is picked as NSArray rather than, say, Any[] or NSMutableArray ?

ljw1004 fucked around with this message at 22:26 on Jun 27, 2014

  • Locked thread