I want to be able to say:
func foo(number: Int<of: 0...20>) {
}
foo(100) // compile time error
I want to be able to say:
func foo(number: Int<of: 0...20>) {
}
foo(100) // compile time error
Unfortunately, no.
However you can check for it at the beginning of foo
func foo(number: Int) {
precondition(0...20 ~= number)
...
}
It is probably better style to use contains
though:
precondition((0 ... 20).contains(number))
While technically fine in this case, ~=
has rather fuzzy semantics. That line means “assert that number
triggers the switch case defined by 0 ... 20
” The definition of a switch trigger may be something besides containment for other types.
~=
is designed so that a type can implement it to integrate with switch
es, but I don’t think it is really intended to be called directly.
O...k, thanks!
I'm doing precondition
now.
I also tried this:
enum Number: Int { case a0, a1, a2, .... a20)
func foo(number: Number) {
doCalc(with: number.rawValue)
}
foo(.a15)
The code look odd..
Right, that's a valid concern. I've been using them a little too liberally.
If you want to wrap the value for checking, that's also a way to do it. Though I'd prefer a single-value struct.
struct Number {
var value: Int
init(_ value: Int) {
precondition((0...20).contains(value))
self.value = value
}
}
I got unexpected result with ~=
in this:
"0"..."9" ~= "55"
<==== this expression is true!
I don't understand why. Is the compile somehow casting "55"
to "5"
(Character)?
I just tried:
("0"..."9").contains("55")
<========== is also true!
...
creates a range of anything Comparable
."some string"
is the syntax for string literals.String
is Comparable
.String
’s sort is undefined. It is supposed to generate an order that is fast, not necessarily one useful for sorting the way users would expect for their particular human language. (I think it is currently byte order or something similar)."0"
"55"
"9"
"55"
is between the strings "0"
and "9"
, so the range’s implementation of ~=
, which happens to use contains
, returns true
.P.S. Maybe you just used strings by accident, when integer literals are what you wanted:
0 ... 9 ~= 55 // false
(0 ... 9).contains(55) // false
Is there a reason why String is comparable? I guess it could be useful for comparison-based data structures like search trees, is that the main idea?
This validation struct is the right approach, IMO. It's like the difference between URL
and String
.
One thing I would change, however, is to make the initializer failable. Otherwise it's just another precondition, like the original code, but in a different place. Most likely, consumers of the API will be forced unwrapping (like with URL.init(fileURLWithPath)
), but it's good to give them the option
What does precondition()
do when it is false
? For example, if Number
here is initialized to 21?
It depends. Read the docs: precondition(_:_:file:line:)
IIRC it uses lexicographic order.
It's a little hard to know with this little context. If the validation doesn't appear that prominently, even the assert
would be fine. Wrapping comes with its own maintenance cost.
It crashes in most environment, except for -Ounchecked
which by its name skip some checking. To add to that, I find the following link to be useful:
And as a rule of thump, use assert
when you check your own variable, use precondition
when you check other's variable/user input, and use fatalError
when it's... well, fatal.
Yes. It is so that those kinds of uses are possible. The String
documentation has this to say about it:
Basic string operations are not sensitive to locale settings, ensuring that string comparisons and other operations always have a single, stable result, allowing strings to be used as keys in
Dictionary
instances and for other purposes.
That appears to approximately be the case, but it must also jump through hoops to respect canonical equivalence and other Unicode complications. Ultimately the String
documentation only says this (along with the above):
Comparing strings for equality using the equal-to operator (
==
) or a relational operator (like<
or>=
) is always performed using Unicode canonical representation. As a result, different representations of a string compare as being equal.
It promises to do something stable and Unicode compliant. But that is all it promises. For example, lexicographical order of NFC and NFD would be different, and it doesn’t say which it does. As a client of the standard library, one’s options are to (a) experiment, (b) look at the source code, or (c) not rely on any particular ordering assumptions. Option C is most advised.
I’m not sure if that was just a typo, or if it is a language learning opportunity. In the the latter case:
The phrase is “rule of thumb”, where “thumb” ends with a silent B. The word “thump” means something else.
I took (b), Swift 5.0 (as well as master) uses NFC, at least on the fast path, but (c) is tempting as well.
That said, at this point, it’s probably prohibitive to change the semantic, and one could try to SE to add it to documentation.
That it is, and they’re not even close on the keyboard. I’ll leave it there in embarrassment.
I’m not sure what stable means, it’s a very specific term for sorting, not comparison.
Funny that I do [θʌmp] on both of them, with lighter [p] on thumb.
How did you write above the main line like that? Even Discourse's quote feature doesn't know how to replicate what you did :p
You can view the raw text of a post. In this case, it is:
The phrase is “[<ruby>rule<rt>ɹul</rt></ruby> <ruby>of<rt>ʌv</rt></ruby> <ruby>thum<strong>b</strong><rt>θʌm</rt></ruby>](https://en.wiktionary.org/wiki/rule_of_thumb#English)”, where “[<ruby>thum<strong>b</strong><rt>θʌm</rt></ruby>](https://en.wiktionary.org/wiki/thumb#English)” ends with a silent B. The word “[<ruby>thum<strong>p</strong><rt>θʌmp</rt></ruby>](https://en.wiktionary.org/wiki/thump#English)” means something else.
@Nevin is correct. A subset of HTML tags work on these forums. I first learned it was possible when someone used a <table>
. I sometimes pull out <strong>
or <em>
when the Markdown parser refuses to pair asterisks properly. I’ve found uses for <sup>
erscript, <sub>
script and <small>
. And at some point I decided to see if it could handle <ruby>
.
I've never even heard of <ruby>
, wacky!
Bless the poor souls who need to implement browser renderers to handle at this crazy shit lol
We’ve implemented the “wrapper struct” approach mentioned upthread in our library here: Refinement types by peter-tomaselli · Pull Request #11 · wayfair-archive/prelude · GitHub
as “refinement types”, which are fairly simple, pretty powerful, and not too weird. It’s the cleanest way I’ve found to do this in Swift so far. Fee free to steal anything you think might help!
Peter
Since Swift 5.1 you will be able to use property wrappers and it will perfectly fit your use case. Check out example use cases and implementations here: