Custom string delimiters in Swift 5
ericasadun.com
ericasadun.com
Judging by the downvotes I seem to have set off the Elixir fanboys. You can't define additional string interpolation syntax with Rust, but you can define custom functions to convert from a string to any given type with the Into trait. You can also use arbitrary delimiters with the raw string syntax.
As another comment pointed out, Scala lets you define the equivalent of custom sigils. Elixir brings good, bad, new, and old things to the table but custom sigils are not particularly new or unusual.
> This system was inspired by the Rust programming language. Rust stacks one or more pounds at each end of a string (and prefixes the letter “r”) to create what it calls “raw strings”, that is strings without further escape sequence interpretation. You cannot incorporate interpolation or coded tabs, new lines, or returns.
“one or more” should be “zero or more”, and the bit about the “r” prefix shouldn’t be parenthesised, as it’s actually the part that makes it a raw string. Also its mention of interpolation is poor: Rust doesn’t have interpolation on plain string literals, but things like the format!() macro perform what is more or less interpolation on their first argument (which must be a string literal), and raw strings work just fine there.
This is not something strings should do; you should be using URL instead. Foundation realized this long ago and has started deprecating string-based path APIs because treating a path as a string exposes fundamental misconceptions very quickly.
> extract regex matches
This is something that is being worked on/discussed, but has not been “solved” yet.
I didn't mean that String should have a "pathExtension" property like NSString. I just want operations like "insert a number before the last period" to be easier to do.
Also, there are a lot more things that are a pain with String. I mean, just the fact that I can't pass a Substring to a function that expects a String boggles my mind.
Anyway, these types of operations come up all the time when working with strings, and these operations are really really incovenient in Swift.
Again, what are these operations? I think most of the issues people have with String is due to hard to discover APIs rather than design issues with String.
Swift has sweet solutions for a few special cases (eg. parse file names, parse dates, parse JSON), but parsing generic text is not something that Swift is good at.
NSString has a rich set of APIs for those tasks (NSScanner, NSRegularExpression, and all the rangeOfString... methods). Swift has pretty much nothing. (There is firstIndex(of:), but as far as I can see there is no way to find the next index, which makes it pretty much useless for most parsing tasks)
Maybe the problem is that I'm just not familiar enough with Swifts String, but until now every time I've had to work with Strings I became very frustrated.
Stuff.tar1.gz would like to have a word with you.
My input parsing code was inevitably a mess of stuff like:
let parts = l.components(separatedBy: ",")
let first = parts[0].components(separatedBy: "=")
let second = parts[1].trimmingCharacters(in: .whitespaces).components(separatedBy: "=")
When I did puzzles in D my input parsing was just creating a regex, matching on it, and pulling out the results.I started to look at how to do regex in Swift and it seemed easier (!) to just use .components(separatedBy:) as required. Google came up with a number of people who have created libraries/extensions that make this easier, but Swift really needs some better regex handling built in.
let parts = l.split(separator: ",").map{ $0.split(separator: "=") },
first = parts[0],
second = parts[1]https://developer.apple.com/documentation/foundation/scanner
I really like swift, but there are times when I feel I need a magic decoder to figure out which edge cases apply. My biggest frustration is that something like this
for view in self.subviews { view in
...
return something
}
Is very different from the naively similiar self.subviews.forEach { view in
...
return something
}
I just wish closures were a more first class part of the language like they were in Smalltalk. If language written in 1980 could use closures/lambdas all the way down even for things like if/else, and keep the deception pretty complete, I don’t understand why swift can’t do similiar. for i=0;i<10;i++ { setTimeout(() => console.log(i), 100); }
and you get 10 calls logging "9". (most languages I've touched do this, JS just makes it worse since `var x` in the loop will not fix it)The second won't do that, since the "view" var isn't "mutated" between calls.
1) view is immutable in both cases
2) GGP is returning in a void block so both sets of code will fail
3) there is really no difference except iteration vs function calls as far as I can tell, you can iterate arrays and use higher order functions built into arrays... which seems normal
4) you can only access the index in (1) by calling .enumerated() I suppose.
To address this argument: the fact that a ‘return’ within a loop exits the enclosing function and a return from within a closure exits the closure is not a Swift problem.
func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil)
It is perfectly valid to call this function using a trailing closure for the latter argument, i.e. animate(withDuration: 0.5, animations: { ... }) {
// handle completion here
}
rendering the `completion` parameter label obsolete and giving no clear visual indication that the trailing closure is a completion handler.Again, I strongly dislike the visual similarity to control flow statements.
[1]: https://www.natashatherobot.com/swift-trailing-closure-synta...
Functions are first class types and values in Swift. Both named functions and anonymous functions can be used as values and can capture values from outer scopes. What’s not first class?
> If language written in 1980 could use closures/lambdas all the way down even for things like if/else, and keep the deception pretty complete, I don’t understand why swift can’t do similiar.
Smalltalk’s approach of using higher order functions for all control structures is more uniform in some ways but is not inherently superior. Swift has statements that perform non-local control transfer (break, continue, return) and designing those to work with closures (presumably only non-escaping closures) would be tricky. Also Swift ‘if’ and ‘switch’ statements can perform pattern matching and bind variables in various complex ways, so again it’s not clear if completely unifying all this with anonymous closure syntax would produce something that is simpler overall than just special casing conditionals and loops in the statement syntax.
I am not sure how this plays out, if you think.. Apple gets the GUI builder only on Apple products, but "community" builds the plumbing, while small groups at Apple or elsewhere, are paid to make sure plumbing + GUI is advancing .. ? If this is roughly true, what benefit does the non-Apple world get here?
You can still use Swift to plug into other GUI frameworks and libraries to make apps on other platforms, and there are a few Swift frameworks for writing web applications such as Vapor and IBM Kitura.
Swift on Linux lacks the Objective-C runtime and therefore the Objective-C-based Foundation and Cocoa frameworks. In their place, the Swift project has been creating a pure Swift replacement.
Linux is also an easy target for cross-platform development in Swift, given that it’s a POSIX OS and a first—class host for LLVM. It’s a great testbed for the pure Swift and cross-platform developmen and tooling before it eventually moves to Windows as a first-class Swift platform.
Clarification: Foundation is being reimplemented in Swift. Cocoa will continue to be written in Objective-C and be macOS-only.
https://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Litera...
Isn't it just yet another syntax for strings with another set of rules? What happens when my string includes """# ? Why not just make """ behave this new way and have one less type of string literal?
Why can't the solution be, "put the ASCII in a file to be read in." ?
##"""
in string """# still in string
"""## // out of string
Swift has two types of string "..." and """...""", either of which can have zero-or-more # at the start and end. Q[This is a literal string.] #=> This is a literal string.
Q!The most literal-est of all.! #=> The most literal-est of all.
Q<So I say 'Hello'> #=> So I say 'Hello'
From there, adverbs are used to sort of expand a literal string's behavior.
For example, `Q:q` (or its more verbose form, `Q:single`) means the string can
interpolate \\, \qq[...] and escaping the delimiter with \. Q:q[A simple string] #=> A simple string
Q:q{Backslash: \} #=> Backslash: \
Q:q!Backslash: \\! #=> Backslash: \
Q:q{This is a \} so not too early.} #=> This is a } so not too early.
In the other hand, `Q:qq` (or `Q:double`) means the string can
interpolate scalars (`$`), arrays (`@`), hashes (`%`), function calls (`&`),
closure (`{...}`) and backslashes. my $bool = True;
my @bools = True, False;
my %bools = False => 0, True => 1;
Q:qq[Scalar: $bool] #=> «Scalar: True»
Q:qq{Array: @bools[]} #=> «Array: True False»
Q:qq (Hash: %bools{}) #=> «Hash: False 0True 1»
Q:qq!Function: %bools.keys.join(' and ')! #=> «Function: False and True»
Q:qq<Expression: { 1.0 + 2.0 == 3.0 }> #=> «Expression: True»
In order to prevent unwanted interpolation such as in "username@email.xyz" or
"https://es.wikipedia.org/wiki/%C3%87", only scalar variables are interpolated
normally. As demonstrated, the array constructor `[]` is used to interpolate
a whole array , the hash constructor `{}` for a hash, etc.Since both `Q:q` and `Q:qq` are so common in the language, they have more usual and succinct forms: single quotes (`''`) for `Q:q` and double quotes(`""`) for `Q:qq`. Furthermore the Q can be dropped so `q` or `qq` (followed by a delimiter) can be used as well.
From here onwards, a small number of adverbs can be used on the quoting constructs `q` or `qq` to further restrict/expand a string's behavior. For example, for a string that only interpolates scalar ($) and closure ({...}) variables, the adverbs `:s` (or `:scalar`) and `:c` (or `:closure`) can be used. This results in `qq:s:c` (or `qq:sc`, `qq:scalar:closure`). For example:
my $var = 25;
qq:s:c<$var: { 3**2 + 4**2 }> #=> «25: 25»
Another example is the use of `q` with the `:to` (or `:heredoc`) adverb
which seems to be the closest construct to Swift 5's custom string delimiters: my $billTheCat = q:to/BILL/;
<------- ____
&&& / \ __ _____,
`-- | o \' ` &&/
`| | o },-'
\____( )__/
,' \' \
/~~~~~~|. | .}~~~\
,-----( . | .}--.
| . /\___/
`----^,\ \
\_/
BILL
[1] https://docs.perl6.org/language/quotingYou probably wanted to use either `q:s:c` or `Q:s:c`.
You can turn off features using the exclamation mark `qq:!a`
It's quite easy to get them wrong since `q` is just a `q` short to be `qq`. ;)