Swift impressions
evanmiller.org
evanmiller.org
Is ARC really a win over non-refcounted GC + escape analysis? Full manual control over stack vs heap allocations and lifetime, I get, especially for games. But reference counting is not deterministic, and can also generate pauses.
@Override has been in Java since Java 5.
Also, LLVM static analyze is so good at figuring out your code path that it could effectively retain and release your memory for you.
Cyclic reference is its only flaw but its something that can easily solved through programmer awareness.
ARC may be less likely to get memory paused on release, but ARC doesn't compact free memory, and therefore fragmentation can cause object allocations (malloc) to become more expensive, possibly leading to pauses.
If you use non-copying GC that doesn't compact (ARC doesn't compact), then there are low pause GC algorithms out there that give pretty good bounds (e.g. 5ms pause).
I'd like to see actual benchmarks of both ARC and say, mark-and-sweep on a mobile device rather than speculation and opinion, and both benchmarks must get the same static compilation treatment. That is, if escape analysis tells you that the lifetime of the object is bounded by the current stack frame, then allocate it on the stack, and don't penalize the non-reference-counted GC by allocating 100% of everything on the heap.
A fair few years ago I worked in the murky world of J2ME games, and a common pattern was byte[] _variables = new byte[1024] so you could ensure there were no GC pauses.
That's not the same as ARC, though. The Java equivalent to ARC would be something like having an array of volatile reference counts to go with your variables and fiddling with those at most accesses.
It's not like tons of games haven't been shipped with non ref-count GC. Minecraft being the most famous, but games on Unity3D/Mono can have non-ref count GC. Lua is shipped in tons of game engines and uses classic GC.
Regardless of whether you are using automatic GC, or if you are using malloc/free, you can't write a high performance game without carefully working around memory issues. Even C/C++ games like Max Payne have shipped with frame hiccups caused by poor malloc/free behavior that had to be fixed with custom allocators.
If you're writing a game, you have to pay attention to what you're doing. But do non-framrate limited games and regular apps need ref-count GC? I suggest no, they do not.
Practically the first piece of advice usually given when someone asks "how do I make my Android app non-laggy" is to avoid allocation wherever possible; even a single frame drop due to a GC pause when the user is scrolling a list, say, can be noticeable.
Low pause GC is possible. See http://openjdk.java.net/jeps/189 or Zing/Azul (absolutely pauseless GC or so they claim)
What's FirefoxOS doing for it's GC?
This doesn't compile with Swift:
class A {
func foo() {
}
}
class B : A {
func foo() {
}
}interface Foo { void foo(); }
class A implements Foo { ... } class B extends A { ... }
If someone renames Foo then A and B fails to compile. If you don't want to use an interface, you do it like this:
class A { abstract void foo(); }
class B { void foo() { ... } }
Yes, it's not exactly equivalent but, this is a rather contrived case that never happens in Java because
a) almost everyone uses @Override because IDEs add it automatically b) Java programmers don't refactor by using VI and editing a base class's method names. An IDE like IntelliJ IDE does all the work automatically. c) if you really want to ensure that a class implements a certain interface, you use a Java interface to enforce it.
This swift feature is interesting, but it's not really anything to sell the language.
I don't think Swift is trying to sell itself based on the 'override' modifier, overflow-checked arithmetic, Unicode variable names, or any of the other minor features which people keep on talking about. It has a far more capable type system than Objective-C ever had. Its pattern matching is far more than "C's switch statement, but without automatic fall-through". Except for backwards-compatibility, it de-emphasizes or eschews the many at-runtime dynamic features that Objective-C had (e.g. creating and modifying classes and methods dynamically). It has tuples. It's a huge departure from Objective-C, not just incremental improvements packaged into a new language (not that it invented these new features, of course), so it's doing more than just addressing 'minor qualms'.
Your bit about compile-time code analysis to automatically insert the cleanup code when data is no longer reachable is actually pretty similar to what Rust does today with owned pointers. The downside is that this doesn't work with "normal" code -- you need certain annotations for the compiler to be able to perform this task correctly. In Rust this is done via region pointers (lifetime parameters) and borrow checking.
[1] D. F. Bacon, P. Cheng, and V. T. Rajan, “A Unified Theory of Garbage Collection,” presented at the Proceedings of the 19th Conference on Object-Oriented Programming, Systems, Languages & Applications (OOPSLA), 2004.
Apple docs:
"Garbage collection is deprecated in OS X Mountain Lion v10.8, and will be removed in a future version of OS X. Automatic Reference Counting is the recommended replacement technology."[1]
[1]https://developer.apple.com/library/ios/releasenotes/objecti...
[2]http://lists.apple.com/archives/objc-language/2011/Jun/msg00...
If we don't use the more common understanding of gc, Apple's documentation doesn't make sense. If we do a substitution of Apple's verbage using ARC==GC, we get nonsense such as:
"Garbage collection (which includes ARC) is deprecated in OS X Mountain Lion v10.8, and will be removed in a future version of OS X. Automatic Reference Counting (which is also part of garbage collection) is the recommended replacement technology."
With the insistence on ARC==GC, we'd have to parse that sentence as garbage collection is being removed and replaced with garbage collection.
For example, what I learned decades ago doesn't include that 2004 paper that convincingly shows reference counting to be one end of a scale that has pure GC at the other end.
Yet, that paper made me realize that reference counting is, in some sense, garbage collection.
On the other hand, I see no big problem in having an ambiguous term. That happen all over the world, also in science. Chemists have 'alcohol' (ethanol) vs 'an alcohol' (a family of compounds that includes ethanol), mathematicians have words such as 'algebra', biologists have roses as a family of plants and as a subset thereof, etc.
What the automatic part of ARC does is, at compile time, analyse the code and automatically add the retain and release messages. If it determines the reference will outlive the stack frame, it adds a retain message. if it determines the reference can no longer be dereferenced (maybe because another object reference is assigned to that variable) it adds a release message.
The runtime characteristics are the same as ARC, it just means the programmer no longer needs to work out where to add the retain and release messages (though they still need to think about reference cycles).
Thanks for making this post, I have been meaning to say something similar for a while now. And, re: one of your other posts in this thread, the GC handbook is excellent. One of my favorite textbooks.
What most people on this site call "garbage collection" would be more accurately called "tracing garbage collection."
The proper distinction would be between local reference counting and GC at the time of release, and global heap traversal from roots.
I hate how they didn't make a keyword out of it, even if it meant breaking code.
I may be in the process of writing one of those. It may be up to 100 pages so far with only a chapter or two remaining. It may be available for release in a day or two.
An example is the switch case fall through behaviour of C. In Swift, by default, switch case no longer fall through, but if you need that behaviour, you can always add fallthrough keyword at the end.
When you think about the above behaviour, it seems so much more natural, and wonder why we have been keeping ourselves bitten by this C language construct and developing muscle memory to prevent it by having break, sometimes with a scope (All cases in a switch scare the same scope within C switch, if I don't remember wrongly).
Part of the switch example is solved in other languages (default intends and scoping), of course. But the subtlety of the fallthrough keyword gave me a strong impression. It felt that it should always be a opt-in all these while, rather than an opt-out as it have always been.
With my limited command of english, I feels that I would do it little justice to the language trying to explains some of its concepts like optionals & mutability hints. Some of these concepts only modify the existing solution only so slightly, but meaningful enough to be impactful.
It also doesn't take a stance in the OO and functional debates. It is both OO and functional. Staying as pragmatic as possible.
Finally, Swift is like a wolf hiding under the sheep's skin. Its a very very strongly typed language. It is very specific about it type. But half the time, you can ignore the type and write it like python or ruby. The magic was type inference, its kinda weird but I like that.
You can almost feel that Chris Lattner might have felt he is reaching the point of diminishing return while optimising LLVM for Objective-C. after all, this is a very old language. He done a great job all these while with LLVM but sometimes, the problem is something deeper. Swift is kinda like Objective-C 3.0 without the backward compatibility.
(P.S. Objective-C is my favourite language before Swift)
If programming language is a sword, Swift is just another sword, albeit one that's very sharp.
> Who cares? Do people develop iPhone apps using Go?
There is no built-in support for people to start caring in the first place anyway. But Go fundamentally is better suited for server-side code rather than applications as Swift is supposed to.
On a different note, Apple has started hiring Go engineers. But who cares huh? https://jobs.apple.com/us/search?jobFunction=MTLMF#&ss=33773...
Does anybody know what is the reason they chose those non-standard behavior for the standard containers?
[1] http://fitacular.com/blog/swift/2014/06/08/apple-ios-tutoria...
"Whenever you assign a Dictionary instance to a constant or variable, or pass a Dictionary instance as an argument to a function or method call, the dictionary is copied at the point that the assignment or call takes place."
Even if I assume that that is an error (they didn't think of inout arguments when writing that), the behavior still doesn't make much sense to me.
Say that I want to do a few things with someObject.someField.someDict. In most languages, I would introduce a helper variable: var items = someObject.someField.someDict and do items[42] = 346; items[423] = 356; etc. That won't work, as it clones the dictionary (shallowly). I find it is just too easy to accidentally clone arrays or dictionaries in Swift.
Also, weirdly, that isn't something the language forbids. It doesn't even make it possible for library writers to prevent it.
I still think we will see some language changes before the official release here in this area because naive users will run into too many weird issues with the current behavior.
For example, if the goal is to have normal function arguments immutable, I think it would be more natural to forbid functions from calling mutating methods on their arguments, unless they are specified as inout.
On the other hand, good compiler warnings might be enough for preventing programmers from accidentally copying containers.
Swift is just another attempt to mix the two, quite a successful one IMO. They kept some warts, probably to maintain binary compatibility with Obj-C, but otherwise I think it's a huge improvement over Java-style languages.
One particular pain point between Java-style and ML-style languages are generics; Java and C# have a common object protocol and thus allow a top type, Object, and run-time type information. So, they must decide whether generics/type parameters are only relevant at compile-time (Java) or are kept at run-time (C#). ML avoids this issue by not having any runtime type information (and no type-testing construct). I haven't yet found where Swift stands, but it's a hard problem to solve.
Swift also doesn't perform type erasure. You can do something like the following, as I believe is possible in C#:
struct SquareMatrix<T> {
let dimension: Int
var backingArray: Array<T>
init(dimension d: Int, initialValue: T) {
dimension = d
backingArray = T[](count:d*d, repeatedValue:initialValue)
}
subscript(row: Int, col: Int) -> T {
get {
return backingArray[row*dimension + col]
}
set {
backingArray[row*dimension + col] = newValue
}
}
}If you have a function as a final argument, you can change this: something(a, b, { }) to something(a, b) { }. Basically, you just put your anonymous function on the outside of the parenthesis.
I think the book's example was something along the lines of sort(arr) { $1 > $2 }. I think that $1 is some kind of default specifier for the first param and $2 for the second, but I'm not sure.
It is composed by Mesa, Cedar, Modula-2, Modula-2+, Modula-3, Oberon, Oberon-2, Active Oberon, Oberon-07, Ada, Spark, ParaSail, ...
There are quite a few distinctly other languages, though. To name a few: APL, COBOL, Forth, sed, Snobol.
Shots fired
Deleted comment
1) override (also in C#, IIRC)
2) The Option type (which, being a monad, also has compositional ability null/nil doesn't have)
3) Case classes
As I understand it, Java has a similar `@Override` annotation:
If you want the equivalent of !@Override, a) you can do it with Java8 annotation types and a checker or b) you can just declare the method private.
I'm sure Swift's version also fails to address all of the edge cases people might want to catch. No type system can be complete and catch every use case.
https://code.google.com/p/chromium/codesearch#chromium/src/b...
I guess the author is not well versed in programming languages history.
More like F# 2.0 in feature set.
Deleted comment