3 ms·
The posts in the first linked series (http://inessential.com/2016/05/ http://inessential.com/2016/05/) seem to mostly focus on how dynamism can avoid the need f
by comex 10y ago
The posts in the first linked series (http://inessential.com/2016/05/ http://inessential.com/2016/05/) seem to mostly focus on how dynamism can avoid the need for boilerplate. For example, he states that the following code is tedious to write and error-prone:
if localObject.foo != serverObject.foo {
localObject.foo = serverObject.foo
changeDictionary[fooKey] = serverObject.foo
}
if localObject.bar != serverObject.bar {
localObject.foo = serverObject.bar
changeDictionary[barKey] = serverObject.bar
}
But there's another language feature that can replace boilerplate, without dynamism and its associated performance and type safety penalties. A feature that's reviled by many, and was omitted from Swift, but serves this purpose perfectly: macros. What if you could write this?
macro_rules! merge {
($localObject:expr, $serverObject:expr, ($($prop:ident),+)) => {
$(
if $localObject.$prop != $serverObject.$prop {
$localObject.$prop = $serverObject.$prop;
changeDictionary[stringify!($prop)] = $serverObject.$prop;
}
)+
}
}
merge!(localObject, serverObject, (foo, bar, baz));
Actually, this is valid Rust code, as you might have guessed if you know that language. I picked it because it has similar syntax to Swift and a powerful, hygienic macro system. (This case is simple enough that a C macro would also work fine without any ugly arcane stuff - you'd have to have a separate macro invocation for each property, but whatever. But Rust's system scales better to slightly more complicated scenarios.)
Admittedly, not everything you can implement with dynamism is as easy to replace with macros. Many things are essentially impossible with the simple pattern matching language used above. In Rust, there is also the option to write a compiler plugin that can do arbitrary-ish things with ASTs, so almost anything is possible with enough work, including things you can't implement with dynamism, but fiddling with AST transformations is hairy enough that boilerplate looks a lot more attractive, relatively speaking.
Even so, I bet macros would satisfy most of the people advocating for "Dynamic Swift". And for the people who hate them - do you really think doing crazy things at runtime is any safer or easier to understand? It's certainly slower.
(By the way, you can implement dynamism with macros. For example, you could autogenerate functions like 'setProperty(name: String, val: Any)' that switch on the name and do the appropriate casting and such. Though depending on your attitude, you might consider this crucial enough that it should be built into the language.)
- catnaroek 10y ago> It's certainly slower. That's the least of problems, since nowadays we have smart runtime systems that dynamically optimize running programs. It's not elegant, but it works. A more fundamental problem is that this approach to programming leads to brittle code, and when it breaks, it doesn't warn you until it's too late.
- comex 10y agoActually, I feel a bit silly and maybe confused, as the 'setProperty' I mentioned at the end of my last post is... just reflection. Which Swift already has, in the form of Mirror. The only reason the Objective-C runtime is needed for that example is that Mirror apparently only allows you to get the values of properties, not set them, but that just sounds like an implementation limitation that could easily be lifted - clearly built-in reflection is considered within the scope of Swift.[1] So it's a bit odd for Brent Simmons to put this in a list of things he's "nervous" won't be possible in the future, and not even mention reflection. Most of the other things in the list seem like they really aren't possible without Objective-C or, in its stead, new Swift features. (They could still be done with macros!) I guess reflection fits into the general category of dynamism even if it is essentially an existing Swift feature. In any case, to respond to your point: Objective-C does not have a JIT, and since there are a lot of advantages to a pure ahead-of-time compilation model (see the mailing list post linked elsewhere in this thread), as a language mainly focused on static compilation, Swift is unlikely to get one in the future just to deal with hypothetical dynamic features. Anyway, even in the relatively small set of languages that are both highly dynamic (going beyond simple reflection) and well-optimized - there's JavaScript, and LuaJIT I guess? and maybe some less common ones, there's PyPy but I don't call that well-optimized - if you actually use the dynamic features it's easy to fall off the JIT happy path and make your whole function unoptimizable. See [2]. But that's getting off topic. [1] In making that thinko I showed my lack of Swift experience: in Rust reflection is done with macros. [2] https://github.com/petkaantonov/bluebird/wiki/Optimization-killers https://github.com/petkaantonov/bluebird/wiki/Optimization-k...
- jonhohle 10y ago