Swift System Is Now Open Source
swift.org
swift.org
[0] Yes, I'm aware of the staffing issues. No need to beat that dead horse again.
- Go aims to be simple enough for many engineers to be productive with little investment.
- Rust aims to be extremely reliable and efficient.
Swift is very complex, and makes many compromises away from reliability or efficiency in favor of application use cases.
Swift may fill an interesting role for a "native C#" that is mostly reliable, mostly efficient, and somewhat productive, but on the other hand, C#, OCaml, Java, Kotlin, and so on already have various answers to that, and they're only becoming better at it.
The only real advantage it has (as far as I can tell) is iOS (and TensorFlow almost as a knock-on of being the only serious language for iOS).
Fair point, Swift will never be as predictable or efficient as Rust (not a negative perse, just different goals). But I disagree on the complexity re: Go. What about Swift gives you the impression of extreme complexity? Go is definitely comparatively simpler but I do not think it is so much so as to put it in a different league.
Also swift as a language doesn't scale well. There are a lot of bottlenecks in the build process that doesn't let you scale simply amongst many cores like you can with C++, Obj-C & C and probably many other languages too. You're also effectively limited to xcode & apple desktops, so you can't go rent out a 100 core build server on AWS for builds like you can for every other platform out there, not that is matters much yet with swift's build scaling issues.
Also stuff like basic debugging often just... dies.
The more I work with a badly scaling language the more I appreciate a design decision like go made with building fast. I hope with generics in go v2 the boilerplate should reduce a lot.
The debugger is still rough, true, but improving. Apple just isn't spending the resources needed to bring lldb up to a great experience in a timely fashion.
Swifts build system can split off enough threads to consume all of your CPU cores, and batch mode did improve things, but it's not actually doing so efficiently. There is a trade off between total compute time used and number of threads used. In compute time consumed, swift is the most efficient when it's single threaded in WMO mode, but this means you can only compile in parallel with separate modules that don't depend on each other. And even then it's not a very fast compiling language itself, multithreading issues notwithstanding
Maybe something has changed recently, but as far as Xcode 12 goes, I haven't noticed much of a difference. I last checked deeply with swift 4.
More details here: https://github.com/apple/swift/blob/master/docs/CompilerPerf...
Combine (Apple's Rx framework) is pretty understandable/usable as well.
When done right, when you actually need the observer pattern, and use it as an event queue I'm sure it's probably amazing though.
https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
BUT it doesn't change the fact that Rx is hard to implement correctly and is often misused when you don't need the observer pattern.
Swift supports LSP now, so you can use VS Code if that's your thing.
for i in 1..<10 where i % 2 == 0 {
print(i)
}
But you can immediately understand how it works, because it's consistent with the rest of the language and reads well. for my $i ( 1..(10-1) ) {
next if $i % 2 == 0;
print $i;
}
Here Perl's post-conditional syntax (which works only on a statement and not a block so it's more manageable) combines well with "next" (Perl's version of "continue") to very clearly convey intent without a lot of extra boilerplate. An additional clause is often just an additional line. Comments after each can provide additional context as needed. I think this is a more flexible way to accomplish the same thing, and more readable in all but the simplest of cases. And for those simplest of cases, I would use a grep, which is also useful in other parts of the language: for my $i ( grep { not $_ % 2 } 1..(10-1) ) {
print $i;
}
Any syntax learned that works as a special case to only a single structure is either a case of missed opportunity or a case of extra syntax that needs to be learned which shouldn't be, IMO. switch i {
case 1...100 where i % 2 == 0:
print("\(i) is a small even number")
case ..<0:
print("\(i) is negative")
default:
print("I couldn't care less")
}
Or generic constraints: struct Vector<T> where T: Numeric {
// ...
}
If you so wish, you can always use any of the functional constructs as well, as in for i in (0..<10).filter { $0 % 2 == 0 } {
print(i)
}One of the biggest criticisms that Perl gets is that there's so many different ways to do things, and that's somewhat deserved, so the question is what does "where" offer that "filter" doesn't other than another keyword and concept you have to learn to understand the language? What's the point if it's not really that much more expressive or clear?
> struct Vector<T> where T: Numeric
Is this really the same thing? This seems like a case where the same word is used to mean something else, even if they are loosely conceptually the same.
So, feedback, from someone whose exposure to Swift consists basically of this article but has eaten a metric crapload of many other braced languages over the decades.
What I can tell is that the programmer wanted to print 2,4,6,8. So the intentional readability is there. However when it comes to understanding how it works (i.e. the language mechanics delivering the intuitive reading) I had lexical concerns. I couldn't immediately tell whether the where-clause acts like a guard predicate in the for-statement or an unbraced if-statement i.e. equivalent to
for i in 1..<10 {
next if !(i % 2 == 0)
print(i)
}
or for i in 1..<10 {
if (i % 2 == 0) {
print(i)
}
}
or even (let's hope not) if (i % 2 == 0) {
for i in 1..<10 {
print(i)
}
}
and in a similar vein the lexical scope and binding of i was not clear to me; some languages bind the iterated variable at the level of the statement, others inside the iterated body (which may even be a closure for all I know), and this has implications particularly for the the value of i after the loop, for the binding of i in any function generated inside the loop (example: print could actually talking to an IO object that defers output by prepending lambdas to a chain - I've seen web containers deferring view rendering this way), for name masking, and for the consequences of any flow-control/continuation/exception mechanism that may cause an early loop exit.I do not know Swift's scoping rules and having read through the introductory guide and the flow control chapter I still can't tell you if the loop variable remains visible after the loop, and what it is bound to if so.
No doubt that if I sat down with a REPL or an IDE it'd hopefully be evident by example within a few seconds, but the claim was about dry-reading, not interactive experience.
I'll leave it there with an admonishment against making assumptions/declarations about the obvious-ness of something you're already familiar with.
So I'm not actually calling Swift a major offender, but noting generally that I don't there's ever been a language in which the intuition gap between intention and mechanics was small enough to be irrelevant.
(something at the back of my mind is now whispering "Scheme", but too quietly to be taken seriously)
Is there a case to be made for other behavior? Or an example of a language that intentionally treats it any differently? (Unless you go out of your way to iterate over a variable you’ve declared in an outer scope in C, but then that’s not really a for-in construct.)
for (const i in [1,2,3,4]) {
alert(i);
}
alert("i is now " + i); // ReferenceError
(Not that JS is exactly known for consistent and predictable behavior on edge cases, of course...)Python I don’t have experience with, and it appears I stand corrected on that front! I wonder how intentional it is, and what sort of use case it enables (and if it’s considered good practice to use).
RangeInclusive::new(1, 10) .filter(|x| x % 2 == 0) .for_each(|x|{ println!("{}", x); });
(though you could write it the same way, for i in 1..=-10 { if .. { .. }}
(1...10).filter { $0.isMultiple(of: 2) }.forEach { print($0) }
Do you mean the use of “\(variable)” for string interpolation? What’s wrong with that?
Using backslash has the advantage that there’s only one ‘special’ character in strings, but of course, also has the problem can escape any character with a backsplash, except for opening parentheses.
Which for is for and would work as for for?
I think D has to be this idea (or disease depending on who you ask i.e. Go is based on the idea of only keeping the simple bits) taken to the extreme - you can quite happily write Java in D but also implement a Java in D all the way down to the metal (merrily metaprogramming all the way down)
So can Perl.
Or the internalization of the managerial imperative for cheap labor, take your pick.
Companies prefer a churn of cheaper juniors happened.
Don’t get me wrong, I love swift but I think that for what you’re talking about constraints are necessary because we naturally shift towards more complex ways of expression.
Dart is the closest I've found to optimizing the surface area of a language while maintaining flexibility like ObjC.
If anything, that's bad, because it invites projects to adopt a impoverished subset of the language that avoids those features, in which case they might as well not exist because you aren't allowed to use them.
The Swift runtime is large-ish, but not outrageously so, and is generally statically compiled-in to the binaries, so there's no dependencies on dynamic libraries.
It is, as you say, quite complex, but still an interesting choice IMO.
C can be exposed as Objective C, but C++ has to go through C (potential objective C++) first.
This is really no different than most other languages.
What it does do is provide good auto binding tools however to expose classes and objects bidirectionally to objective C.
But the C++ story is what you’ve described above.
[0] https://developer.apple.com/documentation/swift/imported_c_a...
and
https://developer.apple.com/documentation/swift/imported_c_a...
There are still assorted gaps in C imports -- a key example is forward-declared structs, that _all_ arrive in Swift as a _single shared_ `OpaquePointer` type: https://forums.swift.org/t/opaque-pointers-in-swift/6875
and afair obj-c interrop is only available/supported on apple platforms
Swift seems to be one step removed from that. I guess you would have to write an Objective-C to Objective-C++ bridge to then use from Swift, ugh.
Seamless in my mind is what D has where name mangling, templates, and classes all work on Windows, Linux (possibly MacOS - I don't have one). Does swift have any of that?
If you are targeting multiple platforms this can get tricky because the mangled C++ symbol will (probably) be different for each platform, which can be solved with a good build system
The only way I would do it and trust it, would be if the binding is generated and tested (separately) automatically, but at that stage why not just write one with a proper ABI.
Also, this may work for simple C++ methods, but once you cross over into vtable territory, you're going to be in a world of hurt.
Also as far as interoperability, I just don't see a smooth path forward between Swift and C++. Philosophically, much of the C++ code you write ends up compiling away or building specialized generated code at compile time. Anything written in C++17 and newer will also have a lot of constexpr code that generates immutable results baked into the final output.
I'd say, wrap your C++ in a simple C API and expose that to Swift (same would apply to Go/Rust or any other language honestly).
vtables are always a pain, but I think the Swift team had some cool ideas about vtables and other dynamic stuff across dynamically linked shared objects..
upd: https://gankra.github.io/blah/swift-abi/ this
It is not there yet but it is actually being implemented on a native level. A quick Google gave me this. [0] [1] [2]
The approach is first-party than what you get with Rust's third-party crates and tools like bindgen, cxx, etc. Swift's C-interop approach is built-in and much more seamless and automated than bindgen's toggles and switches and creating them by hand in with cgo in Golang.
[0] https://github.com/apple/swift/blob/master/docs/CppInteroper...
[1] https://github.com/apple/swift/pulls?q=label%3A%22C%2B%2B+In...
[2] https://forums.swift.org/t/manifesto-interoperability-betwee...
The parent comment I replied to said: "...I cannot find any documentation at all relating to C++ interop." and this some kind of "documentation" that is related to 'C++ interop'.
I would say that Ada and Rust probably compete on some things, but given the history of Ada in industry, it's probably only in fields that already use Ada (aerospace and what-not).
And SPARK 2014 will support ownership specifications.
Rust is the less advanced one.
If you don't know, please don't speculate.
I use Ada professionally and I am experimenting with Rust. Rust has great promise and I am interested to see where it will go, especially as an alternative to C++.
>> it's a bit less advanced than Rust at static checks
Ada 2012 has comparable and in many cases more advanced static checks than Rust with the exception of memory management. This is especially true of the Ada type system (https://learn.adacore.com/courses/intro-to-ada/chapters/stro...) and design by contracts (https://learn.adacore.com/courses/intro-to-ada/chapters/cont...).
If you use the SPARK subset of Ada, you can use advanced tools to prove the correctness of your program. See https://learn.adacore.com/courses/intro-to-spark/index.html
Rust's borrow checker approach to memory management is novel and SPARK is acutally adding similar concepts to the next version of SPARK (https://blog.adacore.com/using-pointers-in-spark).
>> a good bit simpler than Rust and Swift but more complex than Go
Ada is a large and fairly complex language because it was designed for hard real-time, safety-critical, embedded systems and it has been in real-world use for 40+ years. I don't think it is that simple, but judging simplicity is subjective: what one person sees as complex, another person might see as simple. You can browse the Ada 2012 Language Reference Manual and see what you think: http://ada-auth.org/standards/12rm/html/RM-TOC.html
>> a little bit old-fashioned in approach (verbose syntax and all that).
This comes from the Ada design philosophy to be explicit in everything and to prefer the use of keywords over symbols.
"Readability is more important than conciseness. Syntactically this shows through the fact that keywords are preferred to symbols, that no keyword is an abbreviation, etc." (See https://learn.adacore.com/courses/intro-to-ada/chapters/intr...)
Long-life programs tend to be read more than they are written. The Ada way is to make programs easier to read rather than faster to write.
>> I would say that Ada and Rust probably compete on some things, but given the history of Ada in industry, it's probably only in fields that already use Ada (aerospace and what-not).
This is largely true. Ada occupies a niche for aerospace and other safety-critical areas, but has not been widely adopted due to the "uncoolness" factor and the cost of most of the available Ada compilers and toolchains.
I think the popularity of Rust has peaked some interest in Ada as well, but I am not sure if it will cause any change it where either are used.
I would like to see Rust to continue to mature and get adopted for wide-spread use with multiple implementations and a language standard. As it currently stands, many aerospace and safety-critical spaces would not be willing / able to adopt Rust without a language standard and certifications. Here's hoping . . .
An alternative syntax could be helpful for Ada to gain more traction.
This may be true, but it doesn't contradict the claim that Ada is old-fashioned in this regard. It was an old fashion in programming languages to prefer words over symbols, and to try to make programming languages look more natural language-like to make them more readable. See Ada, Cobol, Pascal or AppleScript for some examples. This is much less common with newer programming languages, where it's much more common to favor terseness and shortcut syntax. It's debatable whether this is better, but it seems undeniable that Ada-style verbosity is no longer in fashion.
Swift is only complex if you need it, otherwise very easy, with few caveats.
And it's efficient enough for all application / cli etc use cases -- if Go can do it, Swift can do it even better.
It's not Rust in performance and low-levelness, but Rust is the "really complex" one in its semantics and learning curve.
This might be hyperbole, but if not I'd love to see some examples on how Swift can improve on Go's concurrency patterns.
Yes. A feature well designed for this very purpose.
>Also is GCD green?
GCD tasks are not green threads but they're not direct threads either (even though they're used under the hood). They're more lightweight and much faster to create (than direct OS threads).
[0]: https://forums.swift.org/t/on-the-road-to-swift-6/32862/
If you claim something like this, please obviously back up your claims or in the very least, cite a simple example.
Go isn't simpler, there is just a defered cost engineers pay later on when it turns out one cannot just do away with complexity by deeming it irrelevant.
I agree that from a single sample you can’t reach conclusions, but “it was their fault” isn’t a great defense.
Many large projects may look like a mess but their success is because they got the high level architecture right and perhaps had the moat of a large tech behemoth behind them.
VSCode, Tensorflow, Kubernetes, Go, Typescript, React. These are a few that come to mind.
At a high level, they are all fantastic projects and perhaps messy in their own way, but they are absolutely fantastic, hardened proven codebases with ~millions of users.
Kubernetes is a complex distributed system with over 2M loc, not matter what the language you use there going to be some issues.
It's probably one of the largest open source project out there.
For example C++ is extremely powerful in writing generic code: Make it a template and and provide a set of of traits to modify the behavior and you get a set of algorithms you can re-use for anything – at the cost of unreadable code in the impelemntation (if you aren't careful; with a chance of quite precise code on the call side) and of course with the bloated version in the resulting binary (after compiler instantiated and inlined (thus copied) everything; where the programmer typically doesn't have to care (till the binary is too large to handle) all of it)
I assumed it is about features because there are really a lot of features inside Kubernetes which are not available in Swarm or Nomad by default.
https://fasterthanli.me/articles/i-want-off-mr-golangs-wild-...
The monotonic time thing is an especially good example.
Swift just seems quite more complex for average programmer.
If you're jumping straight into a large, mature code-base I can understand how it might seem complex, but it's very possible to write Swift code which is as simple and readable as Go code. The same can probably not be said for C++ or Rust, where there's a certain baseline complexity which cannot be escaped.
Benching languages against eachother is like pitting birds of prey against eachother, its pointless because they will hunt what they hunt.
This language/framework dispute I though was fever back in bad PHP days has not changed. I'm not saying; 'oh you kids dont know shit' I'm saying the language is not the problem, the problem is the problem, the right tool for said problem is the answer.
You find Swift complex and speak about why, you're not wrong with its application, iOS it does very well, therefore its a tool for an iOS job.
If I grew up just learning Swift and nothin else, I would say swift is the best . Plato's cave springs to mind.
We are all Engineers, Developers, Hackers, Designers and or Code Monkeys.. Don't try to pit against, know the right tool for the job, if you cant find it, make it. With people who can.
I though thats how we roll
I think the problems you’d want to use Go for, the problems you’d want to use Rust for, and the problems you’d want to use Swift for are largely non-overlapping (in spite of whatever similarities they do have).
Swift is a statically compiled, C like language, that can be used for system programming. Just like C, C++, Rust, Go, etc. This is not an accident. It was built from the ground up to do that.
The goal with this OSS library is literally making swift easier to use in projects where you'd otherwise reach for exactly those languages. So, whether you like it or not, it's competing (or at least trying to) in that space (i.e. system programming). Actually, Swift was designed to replace Objective C, which of course was the system programming language that Apple standardized on as an alternative to C decades ago. It's designed from the ground up to be a drop in replacement in any project where you'd previously be using that. So, it's a natural fit for any kind of project where you'd otherwise be considering things like Rust, C++, Go, C, etc.
Whether that makes sense or not in your context is of course up for debate and highly subjective.
For what it's worth, [1] [2] [3] [4]
[1] A type system that can't cope with SwiftUI: https://tonsky.me/blog/swiftui/
[2] More syntax to shake a stick at https://twitter.com/dmitriid/status/1276482336486576133
[3] Even more syntax weirdness https://twitter.com/bradfitz/status/1285302091544576000
[4] Standard library between versions: https://twitter.com/dmitriid/status/1201441652507844608 File manipulation functions on String, great design.
The good and bad of Swift is the regular breaking updates. Sure it’s a pain when things change, but it’s also healthy when they improve, and almost every change has been an improvement.
A language as simple as C can slowly grow without breaking existing source code. But it’s also never been able to address its most significant flaws.
I provided 4 different links showing multiple different features in the language I find suboptimal.
> Sure it’s a pain when things change, but it’s also healthy when they improve, and almost every change has been an improvement.
It's a very dubious statement at the very least.
> But it’s also never been able to address its most significant flaws.
Can Swift address its flaws even with its breaking changes? So far its been piling on more and more syntax, and continuously breaking its standard library (whose design choices like writing to files from Strings are very dubious)?
Not just syntax, but the amount of it, and the amount of special cases in it.
> SwiftUI is not part of Swift, so 1 and 2 are not relevant
SwiftUI exposes deficiencies in the "one of the best designed languages" and shows how Swift fails to scale in complex scenarios.
(1) Shows that its design cannot cope with anything complex. You have to write clunky wrappers for `if` and `foreach` (but not for while and for, apparently), because the design of the language didn't have place for expressions. The type system cannot handle complex requirements of the library and can't provide better facilities than Java.
(2) Shows just how bad the design decisions are in the language that they all but force you to write code this way. There's syntax upon syntax with no internal consistency or actual design to figure out how they all operate with each other.
And Swift UI forces more half-baked escape hatches (like the `some` "type", like the lambda changes described in (1)) etc.
I'll just once again expose my favorite piece of code ever:
guard let self = self { return }
instead of if self == nil { return }
This is not an "extremely well designed language". These are badly thrown together pieces of half-baked ideas.(3) Once again shows just how badly it's designed. Or, rather, how badly the parser is designed that it can't reliably figure out what is going on. In a language that has no significant whitespace you have to care about significant whitespace. Great design.
(4) I'm faulting the design of the standard library that is only compounding the problems already present. Many languages managed to figure out standard libraries that don't make you read and write files from a string object, or need 15 lines (different every year) of code to figure out how to write/read a file. This only continues to show that very little thought is going into this project, as they are being pressured for time to deliver "something".
Oh, and for the last point, I suggest you read the article :P
It amazes how people completely ignore everything against some one thing they can potentially defend.
Once again, SwiftUI exposes deficiencies in the language, no matter if you care about it or not. Let's take it from the top, shall we?
- Swift UI says: hey, I need to have a list of values inside my nice little functions, what can yo give me? Swift: I can give you Java:
static func buildBlock<C0, C1>(C0, C1) -> TupleView<(C0, C1)>
static func buildBlock<C0, C1, C2>(C0, C1, C2) -> TupleView<(C0, C1, C2)>
static func buildBlock<C0, C1, C2, C3>(C0, C1, C2, C3) -> TupleView<(C0, C1, C2, C3)>
static func buildBlock<C0, C1, C2, C3, C4>(C0, C1, C2, C3, C4) -> TupleView<(C0, C1, C2, C3, C4)>
static func buildBlock<C0, C1, C2, C3, C4, C5>(C0, C1, C2, C3, C4, C5) -> TupleView<(C0, C1, C2, C3, C4, C5)>
- SwiftUI: I obviously need need some conditional and list management logic in my nice little lambdas. Swift: well, our "best designed language" can only give you Java. Because our "best designed language" has skipped class on language development of the past 40 years and can't even imagine that conditional statements can be expressions, for example static func buildEither<TrueContent, FalseContent>(first: TrueContent) -> _ConditionalContent<TrueContent, FalseContent>
static func buildEither<TrueContent, FalseContent>(second: FalseContent) -> _ConditionalContent<TrueContent, FalseContent>
static func buildIf<Content>(Content?) -> Content?
> The "some Type" thing is fairly standard type erasure.Once again, the only reason `some` exists is to aid the compiler. Because the compiler in "the best designed language" cannot figure out the difference between protocols and types on its own.
In general, in Swift and you have to constantly manually aid the compiler in everything. Also see `guard` below.
> Your "favorite piece of code" (which, FWIW, is missing an else on the guard) has different semantics than the other snipped you present because it rebinds self to a non-optional type, whereas the second one doesn't.
Yeah, yeah. I've seen the "it's different semantics" argument everywhere. It's not "different semantics". The only reason this exists is because they rushed the language out, and the compiler and the type checker was very limited. The only reason guard exists is to force nullability checks by the compiler. It's an inelegant and clunky clutch to aid the compiler. That is it. "The best designed language" could instead have this:
if x == nil { return }
// the compiler knows that x is now not nil,
// it's no longer an optional type beyond this point
> The parser is largely whitespace agnostic, just like pretty much every other language. Oh, maybe you were going to bring up C++No I'm not going to bring it up, but it's funny how you brought it up.
Actually, the reason I chose to refuse to engage with you about SwiftUI is that Swift doesn’t support ever programming paradigm in existence, nor should it. The fact that SwiftUI is running into issues where it is trying to use language features that don’t exist and then shoehorn them into the language retroactively is not really a great situation. That said, you claiming (multiple times!) that the language had no thought put into it and that it’s the same as Java is just outright trolling/bait at this point. The language has had a huge amount of effort put into it, many of the questionable decisions made earlier have been rolled out; at this point its type system is really at a similar place Rust or Scala’s is.
The lack of conditional statements being expressions (note: the ternary operator does exist) and type narrowing is a conscious choice, not something that the language has to have in order to “be modern” or some sort of evidence that this wasn’t considered. Type narrowing in particular is very common in languages that interface with code that is not well typed (TypeScript with untyped JavaScript, Kotlin with unannotated Optionals and inheritance hierarchies from Java) and Swift has generally had a much better interface with system libraries than that (this being largely controlled by Apple, they can roll out annotations fairly widely). Statement expressions are just a choice that Swift does not choose to have, although as see with function builders perhaps Apple will force it into the language anyways. And type erasure is good not only for the compiler but it’s also a huge benefit for users and API designers: it allows for “class cluster” designs, it keeps users from having to see SomeMonsterGeneric<Wrapper<Type1, Type2, Type3>, OtherGarbage> for no reason.
Of course it shouldn't. But going ahead and saying that "we shouldn't look at SwiftUI" for whatever reason stops most of the discussion about the deficiencies in the language.
Look, even you are saying things like this:
-- start quote --
The lack of variadic generics is an annoying limitation...
The fact that SwiftUI is running into issues... and then shoehorn them into the language retroactively is not really a great situation.
-- end quote --
You are basically repeating my words, but somehow I'm wrong in my assessment.
> that the language had no thought put into it and that it’s the same as Java is just outright trolling/bait at this point.
When you say that "lack of variadic generics is an annoying limitation" and "language features that don’t exist and then shoehorn them into the language retroactively" it's all right. When I say the same things, it's trolling. Got ya.
> The lack of conditional statements being expressions (note: the ternary operator does exist) and type narrowing is a conscious choice, not something that the language has to have in order to “be modern”
That's why SwiftUI has to "retroactively shoehorn" things like `buildEither<TrueContent, FalseContent>` because a "best designed language" doesn't have any facilities to, well, facilitate this.
> although as see with function builders perhaps Apple will force it into the language anyways.
Me: Swift lacks this and that.
You: You are a troll, and you are wrong, and this is a good design decision <literally half a sentence later> it will likely become a part of the language because <a few paragraphs before> there are features that don't exist in the language
> And type erasure is good not only for the compiler but it’s also a huge benefit for users and API designers: it allows for “class cluster” designs, it keeps users from having to see SomeMonsterGeneric<Wrapper<Type1, Type2, Type3>, OtherGarbage> for no reason.
There's literally no reason to have SomeMonsterGeneric<Wrapper<Type1, Type2, Type3>, OtherGarbage>. The only reason `some` exists is, and I repeat myself, because the compiler and the type checker literally can't distinguish between a type and a protocol without the developer babysitting them.
The reason I suspect trolling is that you have repeatedly taken my comments out of context, glommed them with other things that are not related, and then responded to that strawman, plus created what I can only refer to as "bait" because I have to waste my time responding to them when I could be having a much more productive conversation. So tell me, would you rather talk about how Swift's type system is the same as Java, how the compiler is designed by incompetent fools who rush out releases, and how any language that doesn't include the three features you brought up is automatically stupid, or maybe we can discuss this more productively from the viewpoint of "why didn't Swift include these things I like?" or "was SwiftUI poorly designed if it is trying to create new parts of the language out of thin air to support itself?" or "has Swift prioritized the wrong set of features?"
First of all, this is still perfectly valid swift:
if self == nil { return }
But guard is really nice, because it signals to the reader of a code block that if the guard condition can't be met, execution cannot continue past the guard. It does a lot to signal intent which using an if statement for early return does not.It's something I sorely miss in Rust for example.
Since every single language has an if statement, we clearly know what intent an if block signals.
If the if condition is not meant, execution cannot continue. See? Easy.
The only reason guard exists is not to aid the reader, but to aid the compiler to recognise nullability checks. That's about it. It really is a very specific if statement that is given a special treatment. And all comparisons of how great it is compared to an if statement I've seen are hillariously funny in how they willingly lie about ifs. Starting with the actual Swift docs [1]:
> Using a guard statement for requirements improves the readability of your code, compared to doing the same check with an if statement. It lets you write the code that’s typically executed without wrapping it in an else block
Here's how people take it to heart [2]:
> Without using guard, we’d end up with a big pile of code that resembles a pyramid of doom. This doesn’t scale well
Nope, you don't end up with a pyramid of doom, and yes it does scale well, provided you language designers actually design the language.
[1] https://docs.swift.org/swift-book/LanguageGuide/ControlFlow....
Guard has different semantics than if. For instance, I can write:
if self == nil {
... do some cleanup
return
}
Or: if self nil {
... do something else without returning
}
If it's a simple early return, then yes it's pretty easy to tell the intent. But imagine that I have to do some complex cleanup work over many lines before the return. In the case of a guard, I can look at the guard statement and immediately know that this block of code must end the control flow within this function. With an if statement, I have to read and parse the content of the block before I can understand that execution should not progress past this block.This is especially relevant when you're maintaining code which was written by someone else. With an if statement, you might accidentally remove a return statement from an if block which is required for correctness, and you may not find out about it until you run your program (or in the worst case after you release your code, and it causes unexpected bugs in production). With the guard statement, the compiler will enforce this constraint. It's one of many tools which Swift gives you to help you write correct code.
Also, with your example:
if self == nil { return }
I assume you are alluding to languages where self would be implicitly unwrapped in this case, so it can be treated as a concrete instance rather than an optional after this statement. IMO it is a strength of swift that you don't have this magical conversion of an optional to a concrete value which never explicitly written, but is inferred by the compiler. Guard offers clarity and consistency about exactly where the unwrap happens, and it's barely more verbose than a bare if statement. IMO this is a very elegant solution, and in practice it's something I miss in languages which don't have it.Yes, it has. But why? Everyone parrots the same "different semantics" excuse never bothering to ask why.
The only reason `guard` exists is to manually tell the compiler to do a nullability check. And that is it. It's a very small, very specific case wrapped into a separate syntax of its own because the compiler and the type checker are just not good enough.
guard X else {}
is exactly the same as if X is not null {} // pseudo code
but the compiler/type checker are not good enough to know that once null checks are passed in a statement, it's safe to use that value in the code that follows.This leads to horrendous piles of useless code like the one I showed:
guard let self = self else { return }
How can one look at that and say, "yup, that's good design"?> But imagine that I have to do some complex cleanup work over many lines before the return. In the case of a guard, I can look at the guard statement and immediately know
And immediately know almost nothing. Except that it's a very specific `if` case that returns. Which brings us to:
> you might accidentally remove a return statement from an if block which is required for correctness, and you may not find out about it until you run your program (or in the worst case after you release your code, and it causes unexpected bugs in production).
It won't cause issues if the language is actually properly designed. Because the variables you'll use will not checked for nullability in this case. And even Java will warn you with "potentially null value". But Swift can't do that without a `guard` statement. Go figure.
> IMO it is a strength of swift that you don't have this magical conversion of an optional to a concrete value
Yes, you do. You wrap it in a guard statement, assign a variable to itself, and poof, magic, it's suddenly unwrapped.
It's like you didn't even read my comment, I gave a reasoned answer why it's different. It gives a queue to the user that the condition must be met, or else there will be an early return.
The example you gave is also not equivalent - here you have:
guard X else { /* branch A */ }
// Branch B
And here you have: if X is not null {
// Branch B
}
// Branch A
The problem with your argument is that you are taking a subjective preference - that magical unwrapping via if-statements is the best form of unwrapping - and stating it as if it is an objective fact. You haven't actually given any arguments for why guard is an inferior approach beyond basically saying: just look at it, it's bad language design. Why is it bad?> It won't cause issues if the language is actually properly designed. Because the variables you'll use will not checked for nullability in this case. And even Java will warn you with "potentially null value". But Swift can't do that without a `guard` statement.
Again, it's not a question of proper/improper design or a failure of the compiler. The designers of swift made a conscious decision to provide exactly 3 ways to unwrap an optional:
1) the force unwrap `!` operator,
2) the `if let` statement,
3) the `guard let` statement
Just because that is not the exact design you would prefer does not make it a bad design.
You're also ignoring the uses for `guard` beyond null checking. For instance, if I wanted to check that my arguments are within a certain bounds, I could do something like this:
func foo(x: Int) -> Int {
guard x >= 0, x <= 42 else { return 0 }
return 2*x
}
This has nothing to do with "manually tell[ing] the compiler to do a nullability check ... because the compiler and the type checker are just not good enough" - it's about having an explicit language construct to signal that you do not want to continue with the logic of this function if the condition is not met.> Yes, you do. You wrap it in a guard statement, assign a variable to itself, and poof, magic, it's suddenly unwrapped.
These are actually very different things.
In this statement:
if x == nil { ... }
you are taking the conditional (`x == nil`) and giving it this magic side-effect that once it's executed, a new variable of a separate type is created and will replace `x` until the end of execution. Every other conditional simply evaluates to a boolean, so why should this one special case have this side effect where it's also declaring and assigning a new variable?To contrast that with the statement which bothers you so much aesthetically:
guard let self = self else { return }
Here the `let <identifier> = <value>` denotes the fact that you are declaring and assigning a new variable here, which is why the type change can take place. It happens to have the same name as the previous `self`, but every aspect of this is consistent with the rules of the language, and there is no special case being created here.You may not like it, and that's fine, but your personal taste does not reflect an objective truth about language design. Tens of thousands of swift developers around the world are able to understand the motivation for, and benefits of `guard` statements just fine. If you are bizarrely confused or angered by them, it does not mean they are categorically bad.
A guard must return if the condition doesn’t match. There’s no such requirement for if.
I also like that unwrapping is explicit in Swift. ‘if/guard let x = optional’ is the syntax for unwrapping. ‘optional == nil’ is the syntax for checking whether an optional is nil. Why would the latter do any unwrapping? The first time I saw that syntax in Kotlin, I thought that it’s weird to add functionality like this to a normal looking if.
It's ok for you not to like Swift, though. After all, taste is subjective.
It's amazing in situations where performance is critical, or where you have constrained resources. But I'd much rather use Swift in other situations.
God help you if you want to have a swift package with some metal code in it. Rust cargo manages this without a hiccup.
Swift is nice as long as daddy Apple had your use case in mind, God forbid you have to tweak something. Rust feels more "timeless".
Swift for TF is dead.
For server side I’m probably going to use Rust, for MacOS or iOS I’m certainly using Swift, for Android I choose Kotlin, and for Windows I would choose suicide.
Anyway I was trying to use swift for things outside of iOS work to share code and it wasnt worth it, is what I'm really getting at. So agreed on your whole second sentence haha
Oh, unless you're developing GUI stuff. In which case, good luck. Use Qt or something, I dunno.
Swift has many nice similarities with Rust and other current languages from a pure syntactical/language perspective, while aiming to be a GP language. It definitely serves a broader audience than Go, whose main target is server programming. Swift's main target is Apple UI programming, however, the language is capable of so much more.
Which is why Open Source is good news. It may make it escape its Apple box.
Here is one post about writing an Aho-Corasick implementation in Haskell which is as fast as the fastest Rust implementation: https://tech.channable.com/posts/2019-03-13-how-we-made-hask...
I think Swift is where .NET was in its first decade. While capable of so much more, it is limited by its designers and primary purpose so it cannot go beyond. The tight coupling to UI products is a burden an ecosystem carries. Java won in the backend not with is UI, JavaScript with node/npm before Angular reset the frontend and C# just when .NET Core pushed it into spaces it has not been before (apis, lambdas, etc).
Anything on the internet should be cautious of memory unsafety issues. Something like an image processing library I won't consider 'security focused' yet I would trust one written in Rust over one written in C.
You could call Java is niche for the same reason. Some of us want to write native, low overhead code in a language that has a sane design (only disparaging C++ here). It's about time C++ had more alternatives.
While it’s true that Rust shows promise in security and embedded, some of the early adopters have been in the server side and microservices.
I prefer the landscape for ML not to be fragmented based on non-essential qualities like the language that is used.
How great is it that researchers publish code in the same language, and everybody can use that code immediately without having to learn language X and/or porting the implementation?
I also think S4TF's approach has been really neat here: there's a really nice python interop so you still have access to the entire body of work and tools in python available, and it basically feels like writing native swift code.
I primarily write C++ and Python and never feel like this.
But in general, c++ to python is an awkward comparison because c++ is extremely low-level by comparison. So you do get static typing, which is nice, but you also get a lot of other issues to deal with - namely manual memory management - so with either python or c++ you have a high probability you will have code which fails at runtime. It would just be the case that in c++ most of the time it would be because you handled memory incorrectly, whereas with python it would more often be because you made a type-related error. Swift is much more comparable with Python in terms of reducing cognitive load by obviating low-level details from the programmer.
Don’t get me wrong, I love Swift. It’s an absolute pleasure to work in and my first language of choice for projects targeting Apple platforms. But I’m very skeptical of its long-term potential outside of that ecosystem, especially with Apple’s move toward custom silicon and relying on hardware-level implementations of what would traditionally reside in software. This approach has worked out well for Apple with the rest of their product line and I’m completely on board from an engineering perspective - but it’s a path that will not result in higher cross-platform adoption.
the alternative to python is julia
From looking through the swift official site, it just seems like a new C# or Java with ahead of time compilation.
The only slightly unique bit I can find is that the syntax is a bit more JavaScript inspired.
Am I missing something? Or that's it? It's just the C# of Apple?
For example, Rust has borrow checking for zero cost memory safety.
Go has concurrent sequential processes and its accompanying goroutines.
Haskell is a fully pure language.
Python has cool indent based syntax that looks like pseudocode.
Ruby is objects all the way down and has this unique concept of blocks for passing code around to be yielded.
Clojure has immutable persistent data-structures as default and software transactional memory, while also being a Lisp bringing macros and all to the JVM.
Erlang has actor concurrency.
Etc.
So in a similar vein, what would be Swift's innovation or originality here?
A lot of really good programming languages are “uninteresting” in this way, and that’s probably a good sign, not a bad one.
How long has Swift been available outside of Apple platforms? And I don't mean experimentally available either. They only posted an announcement a few days ago where Swift is deemed ready for early adopters on Windows. That certainly does not sound production quality there.
Yes: Swift is now (and has been for a while) the standard language for developing iOS and MacOS apps. That makes it important completely independent of any features it may or may not have.
So, if you have to choose between making your app for iOS first, or Android first, then in addition to any consideration of markets which might or might not apply to your business model, you will have a very strong incentive to choose Apple for time to production.
I would love to see more serious competition on that front.
And up until now, I was thinking I'll try Swift the day I'm forced too, because I'm working to develop an app for Mac or iOS.
But then I started seeing some comments like: "For me, Swift is currently the most interesting language". So I thought I might be overlooking something.
The most innovative feature I can find is null safety, which is alright, but I guess I've had my fun with it with Kotlin already. Someone mentioned good ABI compatibility, that is interesting, and I'll need to read up on that. Others say, it's just a nice mix of modern features in a well maintained package. That's great as well, you could argue C# and Java being older have some less modern aspects lingering. But that's nothing that makes me want to jump in it and try to use it for my next project.
To have adopted any of those other languages requires dramatic changes to a huge amount of platform APIs, along with on-going challenges of divergence. Put another way, any other language would have basically forked the entire platform.
The Swift developers definitely have ambitions beyond being a compatible with Apple's existing SDKs, but that's the fundamental thing Swift does that no other language can do.
For me Sum Types and pattern matching in particular are an absolutely massive improvement over languages that only have classes/structs. They make statically typed languages feel almost as expressive as dynamic ones.
The weird thing about typescript is that this incredible power and expressively must be backported into the runtime environment. And because of that, the promises that the type system makes are unreliable and also lag way behind the actual language features that are implemented.
I hope these criticisms are read in the proper context: I absolutely love TypeScript, and find it to be a really special unique oddball in the world of language design. I wish it had been ReasonML instead of TypeScript, but TypeScript is incrementally working it’s way there and bringing the whole js community with it, so I can’t complain.
Edit: Prediction: prepare for switch statements to become popular as the typescript community gradually adopts exhaustive pattern-matching types.
A poor example, but this compiles without error and crashes at runtime:
let x: string = "foo"; (x as any) = 1; x.substr(0);
Now, technically, you can do this sort of thing in most, if not all, languages, but this happens organically more often with typescript due to many libraries being written for plain javascript and being looser on their types, or type definitions getting out of sync with the libraries they are written for.
So no, it doesn't really have a whole lot of "innovation or originality" -- but it essentially takes some of the best ideas of modern language design and wraps them into one general-purpose language for application development, and as a result I find it to be a really useful and practical language.
It has seamless interop with Objective-C and C, and can be mixed with about any language LLVM/Clang can handle (as long as you have C headers), compiling it all down to a small, self-contained binary.
For now it's mainly useful on Apple platforms, but there's interest and efforts in cross platform from both Apple and the Swift community, so there's a lot of potential for it to be a great language for the main body of application code, with individual bits of functionality written in languages that make the most sense without too many layers of adapters or wrappers.
Seems like a viable niche to me.
The interop actually has lots of seams. A huge engineering effort had to be made and has been made to paper over those seams, but they are definitely there.
Calling conventions are gratuitously incompatible, objects have to be converted at API boundaries at significant cost, the meta-systems are incompatible, etc.
They certainly didn’t just make run-of-the mill choices for all language features. Some non-standard design choices they made (for better or for worse):
- Reference counting without any automated cycle-breaking
- Collections are value types (implemented somewhat efficiently by having copy-on-write collections)
- the Character type is closer to what ‘normal’ people think a character is (https://developer.apple.com/documentation/swift/character)
- consequently, string length is closer to what users who don’t know Unicode internals expect it to be.
- Arrays are ‘different’ (‘inherited’ from NSArray. See https://ridiculousfish.com/blog/posts/array.html)
- protocols are a bit like interfaces, but protocol conformance can retroactively be added to classes, even to ones you didn’t write or don’t have the source code of.
I'm sure I'm missing some nuanced downside to this, but this sounds fantastic. I've never fully understood the difference between Unicode code points and code units[0], and would love to think less about this sort of thing in Java (for ex. when using String#toCharArray).
[0] I'm just regurgitating language from the String javadoc, this sentence might not even make sense.
Most normal people assume Unicode grapheme to be characters. That would be the set of symbols you'd consider a single letter if you were to visually count the number of symbols in the string.
In Unicode though, some code points are non visible, yet are part of the string. So for example, the character at i+1 for some match against a letter might not be the next visible letter. I can see this causing issue either way.
Honestly, I'd say it's best to just learn this, it you'll have some weird bugs one way or another.
Basically, you have code units, those are the smallest chunk of bit that has meaning in Unicode and thus can be sent over a wire, streamed or decoded. In UTF-16 encoding, which is what JVM uses, code units are 16 bit.
The history helps. In the beginning, each character in Unicode was 16bit. So you could represent all Unicode characters with 16bit only. Later, there were even more characters added, and it couldn't fit into 16bit. So UTF-16 where the 16 tells you the code units is 16 bit no longer could represent all characters in one 16 bit unit. Thus code points were invented, those are characters that span two code units 16bit + 16bit. Together they represent the new characters that didn't fit in the single 16bit range.
So nowadays, it actually takes 21 bits to represent all Unicode characters. There's three encodings: UTF-8, UTF-16 and UTF-32. Their number correspond to the bit size of their code units. In UTF-8 we break each character into 8 bit units. In UTF-16 we do so in 16 bit units, and in UTF-32 into 32 bit units.
Ok, now back to measuring length. We can say tell me the number of code units used to represent the string. That's what Java's string.length() does. Or we can say telle the number of bytes needed to represent the string (a byte is 8bit). That's what converting to byteArray and getting the length of the array does. Or you can say tell me the number of code points (Unicode characters) the string contains. In UTF-16 a code point can be 16bit (composed of one unit only), or it can be 32 bit (composed of two units). But not all Unicode characters are visible, so the user might be surprised to get a length that is greater than what it counts visually. So you can also get the number of grapheme in the string, which are "visual characters". In Java you can use BreakIterator to count those. That said, Unicode grapheme don't always make sense to what each speaker of each language would consider a character. That's for example some languages might consider a combo of two letters one character with one pronunciation, etc.
Finally, I'll say there's another interesting length. It's the font width in terms of physical measures like pixel count.
So basically, each measure might be most appropriate depending what your measuring for.
I think the real issue is that we didn't adopt new terminology of Unicode yet. You should try to start referring to things as code units, code points, grapheme and font width/height. And stop using the word character or letter.
And then just make yourself a little library that has string.codeUnitCount(), string.codePointCount(), string.graphemeCount() and string.pixelWidth().
And when you don't care about the difference between these, I'd argue that code unit count is the best default for length, which is why I don't actually disagree with string.length counting code units. Cause I think of string.length from the perspective of looping over the smallest units of the string.
Graphemes are comprised of code points, code points are comprised of code units, and code units are a chunk of binary of variable length depending on the UTF flavor.
UTF-8 uses smaller code units so that strings containing only ASCII (for ex.) are of optimal size (in terms of memory). UTF-32 would mean each "character" takes up 32 bits regardless.
I think the String javadoc could be clearer here. The class overview mentions these concepts but the methods are not as forthcoming.
Thanks!
So (not Swift, nor, AFAIK, any other existing language)
for i = 0 to stringlen(s)
print s(i)
would be O(n²), so slow for long strings. It’s rare to have code that accesses the n-th character of a string without accessing all earlier ones, though, and idiomatic code for c in s
print c
can be efficient (not as efficient as iterating over fixed size units, but not dramatic, either)Also, requiring String to know of what code points in Unicode are “combining” means carrying a few tables around in the implementation. That could be problematic when porting Swift to devices with small amounts of memory. It also, I think, ties Swift to a version of Unicode. You cannot predict what code points in future versions will be combining characters (https://en.wikipedia.org/wiki/Combining_character)
I also think there are a few corners where Swift doesn’t reach the goal of “a character is what naive users expect”. Ligatures in Unicode might be problematic. For example. “fl” is a single Unicode code point, but, ideally, would be two characters “f” and “l”.
Oh nothing. It makes sense for Apple to want a more modern language to replace the now aging Objective C. In turn, that meant Swift was not on my list of languages to try, but instead on my, possibly a language I'll be forced to use one day list, just as Java, C#, JS, and all are, by simply being defacto languages for some platform which depending what you work on, you have no choice over.
But then I started seeing people in the comments claiming things like: "Swift is one of the most interesting languages right now". So I was like... Hum okay, what did I overlook?
Now, I'd be okay with people saying that it improves drastically on C# and Java. If people think Swift is a dramatic improvement because of the sum of its part, like just little details here and there that end up making it much better, and they think that in turn could lead Swift to replace both Java and C# if it gained support on other platforms. That could make it quite interesting as well. So I'd be up to listen to those arguments as well.
Arrays still are not guaranteed to be contiguous in memory, though. If you want that, there’s ContiguousArray (https://developer.apple.com/documentation/swift/contiguousar...)
Isn't copy on write data structures mostly discouraged idea these days?
If you've been putting up with the [lack of] iOS API ergonomics for years, by all means, Swift will look like a substantial step forward. If you're used to thoughtful and quality APIs, the marriage between Swift and NSDrunkApiDesign is an incredibly unattractive proposition.
I really just refuse to tolerate those APIs on platforms (.Net) and languages (Rust stdlib) where more sensible APIs are available. If there were an alternative stdlib for Swift that lacked/wrapped the iOS quirks, I'd probably be all for it.
.Net has done that, with multiple platforms.
Dart has done that, with multiple platforms.
Apple doesn't care for anything except iOS. That is why Swift won't be taken seriously on anything except iOS.
You can still say it's a facade when using things like UIKit, but as we've seen in the past few years w/ SwiftUI that is changing. It's already no longer the case if you're doing anything related to heavy duty computation [Accelerate, Metal & others have Swift-specific APIs now] or networking [SwiftNIO].
I especially like that you have file operations defined on String type.
Also, how is it that a "well-designed and polished" standard library doesn't have a means to write to a file?
However, for the project I was on, when I was working on it, Swift on Linux was a massive pain in the ass, mostly due to documentation and dependency hell. Documentation was extremely useless; the number of times I was told "oh yes there's a swift way to do that!" only to find out the 'swift' way was to wrap a Cocoa library or just drop in some Objective-C module. If I recall correctly, there was an issue with pthreads not being properly implemented at the time, relying on some hacks to get it to 'work' while they figured out a 1.0 implementation. We got it to work, eventually, but the hoops we had to jump through really pushed our team to Rust as our general purpose systems language.
I'm glad they seem to have got it working, but I'm never subjecting myself to trying to get Apple's nonesense working outside of iOS or macOS again.
I think the Linux support that already exists is an awesome start. But the only realistic way to see more from Apple on this is if they themselves start to deploy critical Swift web-services on their own backend infra. (I'm assuming here that they run Linux systems somewhere in their stack.) That will give them the incentive to take it to the next level. Until then it's largely left to the community to find the energy and time to do this.
Apple has enough in the bank to do it as well.
If you're not targeting an apple UI the choice of swift is entirely confusing because it has even less of an ecosystem to build off of than where it's popular.
https://github.com/quicwg/base-drafts/wiki/Implementations
Phrased another way, your language should be participating in the future of HTTP, which is HTTP3 aka HTTP-over-QUIC. Swift's absence here indicates, to me, that Swift does not take itself seriously as a tool for delivering server side systems.
IBM dropping swift was another pretty strong indicator to me. They really tried, they wanted to believe. But this seems like an insular, closed off world, however much they keep going through long lengths like this effort here to open themselves up & make themselves accessible to the rest of the world. Their attempts to build bridges haven't seemed to make people be very interested in transitting over to their parcel of land, the advantages aren't clear, choices of language just don't seem that relevant, there's some advantages but overall the day to day won't be radically different except that you'll be an outsider hanging out with a bunch of people mostly entirely doing iOS. I'd be happy to be wrong, seems decent enough, maybe there's some real differentiation that truly improves life, but it also seems like it's a C# type situation, where it exists & is developed only to keep the natives in spirits & from getting restless.
I want to re-iterate that I think Swift seems pretty ok. More than not-bad. But languages just don't seem that relevant to me any more. Rust is being extra-strict, but otherwise, the feature-sets of languages doesn't seem very notable. There's some preferences & styles, some community favor that distinguishes languages, but by & large the work is not that different. I'm not sure what I would suggest to Swift to help themselves rise above, to underscore their own meaningfulness, in this kind of murky abyss-like scenario I've painted. I do think trying to win some AI champions makes sense; python seems to be unshakeable there, but that also means there's opportunity for better/different. Trying to get some web-developers web-platform folk on your side is usually a pretty big win, but not easy, & very factionalized already. It's weird days for languages.
Nah. It's fine to leave any networking to external libraries.
Some trivia, not necessarily a recommendation: Node.js is the only language I know of working towards HTTP3 support in the platform (also in this link, evidence that I may be biased in my priorities):
"Swift uses Automatic Reference Counting (ARC) to manage memory."
Rust's Rc/Arc can still selectively use borrowing, which guarantees the level of efficiency that in Swift may or may not happen depending on the optimizer. A borrowed Arc can often stay borrowed across many non-inlined method calls, which you're unlikely to get in Swift.
At this point I don't even care about how good their language is. Apple has a very, very long way to go before I can trust them on anything of that magnitude. I would instead assume they WILL pull the rug from under developers for any random reason.
(And I say this as an iOS developer)
Most Linux users here likely use one or two out of three of these on a weekly basis. Many likely use all three on a weekly basis. Some use all three daily.
WebKit is probably pretty rare outside macos, most browsers will be built from Chromium/Blink instead.
LLVM is developed by many companies these days, including Intel, Sony and Google.
Wrong. Upstream CUPS on Apple's github has support for everything, even systemd.
> WebKit is probably pretty rare outside macos, most browsers will be built from Chromium/Blink
GTK's WebView (and browsers like Epiphany aka GNOME Web) use WebKit, complete with Apple's web inspector / devtools.
> GTK's WebView (and browsers like Epiphany aka GNOME Web) use WebKit, complete with Apple's web inspector / devtools.
Good point, Qt's legacy HTML engine (Qt WebKit) is, well, WebKit, too. The newer Qt WebEngine uses Blink. I suspect this is a common pattern with components built on KHTML/WebKit before Chromium became Blink. In any case, Blink is clearly the fork that won.
As a side note, the approach that Swift is taking here is exactly what I really like about the Zig programming language. The standard library nearly exclusively takes the approach of wrapping the system calls so you get nice Zig error types rather than the archaic return codes. These things go a long way in making correct usage of really essential but hard to use APIs possible.
What we have now is the acknowledgement that after 60 years even 10x C developers don't write corruption free code.
Most people on this thread are the ones that care a lot about the Swift programming language. Most of the ones that would understand the joke are not reading this thread.
> DescriptionThe Society for Worldwide Interbank Financial Telecommunication, legally S.W.I.F.T. SCRL, provides a network that enables financial institutions worldwide to send and receive information about financial transactions in a secure, standardized and reliable environment.
https://en.wikipedia.org/wiki/Society_for_Worldwide_Interban...
I'm seeing a distinction without a difference, but clearly you aren't.
There is some functionality you can access from glibc at link time, but not all of it (as some are implemented as macros). Even then, that's glibc providing the interface, not Linux.
As the other commenter said, this is subtle (and probably non-consequential) for most people, but if you are writing an abstraction over the system interfaces, it becomes very significant to your codebase.
As an example, you can lookup how Go does syscalls on Linux. It has some important consequences for their low-level design decisions: https://utcc.utoronto.ca/~cks/space/blog/programming/GoSched...
Linux's various APIs used for container frameworks also tend to be per-thread, not per-process; that can be both useful and a giant headache, depending on context. It's somewhat ironic that Go was used for Docker as Go is pretty much the worst possible language you could choose in this regard. Go deliberately and thoroughly obscures native thread and process semantics. IIRC, Docker was already well along and established before Go even introduced an API for pinning a goroutine to a machine (kernel) thread. I once ran across a comment where the author of (I think) runc lamented his choice of Go. But I haven't been able to find it again, so it's entirely possible it's a misattribution on my part.
Linux itself does not provide a libc or other similar system library implementation (even NT has ntdll as the stable syscall layer), and it’s the syscall numbers and parameters themselves that are the stable interface.
https://utcc.utoronto.ca/~cks/space/blog/unix/UnixAPIAndCRun...
> A few Unixes explicitly say that the standard C library is the stable API and point of interface with the system; one example is Solaris (and now Illumos). Although they don't casually change the low level system call implementation, as far as I know Illumos officially reserves the right to change all of their actual system calls around, breaking any user space code that isn't dynamically linked to libc. If your code breaks, it's your fault; Illumos told you that dynamic linking to libc is the official API.
> Other Unixes simply do this tacitly and by accretion. For example, on any Unix using nsswitch.conf, it's very difficult to always get the same results for operations like getaddrinfo() without going through the standard C library, because these may use arbitrary and strange dynamically loaded modules that are accessed through libc and require various random libc APIs to work. This points out one of the problems here; once you start (indirectly) calling random bits of the libc API, they may quite reasonably make assumptions about the runtime environment that they're operating in. How to set up a limited standard C library runtime environment is generally not documented; instead the official view is generally 'let the standard C library runtime code start your main() function'.
The kernel's API (which isn't C, but assembly language, as it relies on special opcodes) might be guaranteed stable, as it is in Linux, but even so there are or might be reasons you should call into libc anyway, and take advantage of the official functionality there.
- make porting to new architectures easier (have you tried writing syscalls wrappers in e.g. golang's insane assembly syntax? Not a fun time); - not break anyone's fucking LD_PRELOAD hooks!!
I can't see how that isn't offering a C interface.
I guess I should just stop since you're making a distinction I just am not getting. I realize glibc doesn't == syscalls, but I don't see how that's relevant to the article.
Golang authors completely ignored FreeBSD's policy and went with syscalls directly because "they don't change in practice" and that is infuriating. Porting to new architectures is much harder, for one.
The most famous one being MinWin
https://arstechnica.com/information-technology/2007/10/core-...
During Windows 10 that happened also a couple of times.
If linux is not an operating system, what is? Gnu/linux is a very popular operating system offering a c interface, as is android linux. I do not know of any linuxoid operating systems not offering a c interface.
> a new library for Apple platforms that provides idiomatic interfaces to system calls and low-level currency types
In other words, it's a set of native, type-safe Swift APIs that wrap the usual C system calls.
> System pervasively uses raw representable structs and option sets. These strong types help catch mistakes at compile time and are trivial to convert to and from the weaker C types.
> Errors are thrown using the standard language mechanism and cannot be missed. Further, all system calls interruptible by a signal take a defaulted-true retryOnInterrupt argument, causing them to retry on failure. When combined, these two changes dramatically simplify error and signal handling.
> FilePath is a managed, null-terminated bag-of-bytes that conforms to ExpressibleByStringLiteral — far safer to work with than a UnsafePointer<CChar> [Swift's spelling of `char *`].
I hope they meant in case of failure with EINTR.
var md5: String {
// The reason we are declaring these here, is so we don't have to actally import the CC module. We will just grope around and find the entry point, ourselves.
/// This is a cast for [the MD5 function](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CC_MD5.3cc.html#//apple_ref/doc/man/3cc/CC_MD5). [The convention attribute](https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID600) just says that it's a "raw" C function.
typealias CC_MD5_TYPE = @convention(c) (UnsafeRawPointer, UInt32, UnsafeMutableRawPointer) -> UnsafeMutableRawPointer
// This is a flag, telling the name lookup to happen in the global scope. No dlopen required.
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
// This loads a function pointer with the CommonCrypto MD5 function.
// [dlsym](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html) is a symbol lookup. It finds the symbol in our library, and returns a pointer to it.
let CC_MD5 = unsafeBitCast(dlsym(RTLD_DEFAULT, "CC_MD5")!, to: CC_MD5_TYPE.self)
// This is the length of the hash
let CC_MD5_DIGEST_LENGTH = 16
guard let strData = self.data(using: .utf8) else { return "" }
/// Creates an array of unsigned 8 bit integers that contains 16 zeros
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
/// CC_MD5 performs digest calculation and places the result in the caller-supplied buffer for digest (md)
/// Calls the given closure with a pointer to the underlying unsafe bytes of the strData’s contiguous storage.
_ = strData.withUnsafeBytes { (inBytes) -> Int in
// CommonCrypto
// extern unsigned char *CC_MD5(const void *data, CC_LONG len, unsigned char *md) --|
// OpenSSL |
// unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md) <-|
if let baseAddr = inBytes.baseAddress {
_ = CC_MD5(baseAddr, UInt32(strData.count), &digest)
}
return 0
}
// Convert the numerical response to an uppercase hex string.
return digest.reduce("") { (current, new) -> String in String(format: "\(current)%02X", new) }
}
As a Swift programmer, the above hurts my heart (but it works very well).[0] https://github.com/RiftValleySoftware/RVS_Generic_Swift_Tool...
extension String { var md5: String { let computed = Insecure.MD5.hash(data: self.data(using: .utf8)!) return computed.map { String(format: "%02hhx", $0) }.joined() } }
This is one of a couple of computed CC functions in a very general-purpose StringProtocol extension. I wanted to reduce as many external requirements as possible. I don’t even like importing Foundation, if I can help it.
Very shrewd from Apple, with linux on ARM looking the next big leap for cloud computing (amazon etc) being able to program in swift natively on a mac running apple silicon and host in an ARM box on the cloud, having open sourced the systems api, is a very attractive offering.
Currently the top two comments suggest that Swift looks compelling for this use case, but I don't really see it.
This is in contrast to Rust, where more explicit memory management makes GUI frameworks a bit tedious. Rust is more explicit and gives lower-level of control, but borrow checking favors simple code over abstract interfaces.
To me Swift is more like native TypeScript, and a more practical alternative to JavaScript and Python for app development. Rust is a more direct replacement for C++, because it offers similar level of performance and control over every byte in the program.
Rust's compiler doesn't dare to insert any implicit allocations or non-trivial code itself, and will make programmer make every choice intentionally. Swift's compiler does whatever it takes to implement whatever abstraction it presents.
This, and Foundation, are frameworks that allow you to write non-gui linux apps in swift (e.g. swift on the server) - and these could potentially be ported to windows as well.
This announcement concerns Swift System, which provides a wrapper over UNIX functions like `open'. Since those functions come from C, they do things like using integers to represent files (``file descriptors'') and setting errno to indicate failure. System wraps them to make them into proper Swift functions that throw exceptions and make full use of the type system. It has been open-sourced and Linux support has been added.
“... provides idiomatic interfaces to system calls and low-level currency types.”
Apple's branding of SwiftUI and Swift is a bit of a double-edged sword, I think. The former is a highly proprietary, undocumented (but beautifully engineered) walled garden that only works on Apple hardware, and only recent OS versions at that. The latter is open source and purports to be a general-purpose, cross platform language, comparable in scope to C++, C#, Go, Rust, Kotlin, and other comparable contenders. They have only themselves to blame if some of the perception of the former rubs off when people think about the latter.
Unlike most comments here, I felt that Swift was a Python replacement to me.
"One of these things is not like the other, one of these things does not belong"
I mean, it kind of fits, it works, but I did do a quintuple take trying process & make sure I was reading this first line correctly. Posting just to share. Read a little more to confirm, yeah, system calls & currency. Check & check.
One other idle thought, it would be interesting for something like the web platform to try to expose it's api's in a polyglot fashion. For some reason, this exposure, of Swift trying to open up more of it's platform to other platforms (that makes sense in context i swear) makes me think, how can the web platform keep expanding to offer more?
We're seeing really interesting neat early indicators with projects like Rust's web-sys, to wrap & expose the web platform in rust-webassembly. But what would it look like to try to expose & make useful JavaScript's new Temporal standard library, or Intl, or currenc... oh wait we don't have currency. ;)
It does stand to reason, I guess, that currency is as fundamental to Apple as system calls are to Linux.
For example, although there are a variety of range types in the Swift standard library ('Range', 'ClosedRange', 'PartialRangeFrom', 'PartialRangeUpTo', etc.), 'Range' is considered the currency type. Similarly, among string types, 'String' is considered the currency type, as opposed to 'Substring', 'StaticString', etc.
Like currency (money), the idea is that APIs in different libraries across different domains of programming will generally take values of the currency type as input and produce values of the currency type as output unless there's a good reason to use a different type.
For Swift System, the stated goal is to provide low-level currency types; if that goal is accomplished, other users of Swift can rely on these types instead of supporting multiple disparate third-party wrappers of system calls that may provide similar functionality just so that they can interoperate with other libraries.
https://www.google.com/search?q=swift+evolution+%22currency+...