> Aha, now I understand :-)
>
> Perhaps "in order to detect potentially undesired behavior at compile time"
> would be even clearer?
Sounds much better, thanks!
> - there may be other types you may not want to use for interpolation - as
> mentioned in the proposal, e.g. private data structures that would expose
> something you want to keep private, various enum values, etc. Which is why
> I've started thinking about making a protocol that would indicate the type is
> discouraged being "interpoled". I've thought about this and decided to make a
> more robust and customizable solution.
>
> I'm not sure if this is a strong enough motivation.
> The customization point already provided by the language is
> CustomStringConvertible. That's the place where one can provide a readable
> description, hiding implementation details.
Yes, but this is the other way around. Since it is allowed to interpole types
that are neither CustomStringConvertible or CustomDebugStringConvertible, it
might be a good idea to take an approach from the other side as well and
disallow some of them from being interpoled.
> - both .description and .debugDescription are mentioned in alternatives for
> the Fix-It.
>
> The direct use of .description and .debugDescription is discouraged in the
> API docs, so I don't think this is a viable option.
Two options then:
a) introduce a new variable on Optional, e.g. .optionalDescription which would
stringify the Optional into what's the current behavior. Also,
.valueDescription could be introduced, which would either print "nil" or
description of the value it's wrapping (by invoking .description on values that
are CustomStringConvertible, or using printDebug).
b) within the declaration of these variables on Optional, specify that this is
the designated way to stringify the Optional. There is IMHO no reason other
than both values being used internally for various tasks and providing a user
unfriendly representation of the object. Both .description and
.debugDescription should have no side-effects.
> There are many people oposing this and expecting the Optional() wrap around
> the value, indicating the actual type. Actually, including me - I agree it
> can be useful for some types of debugging since in what you wrote further,
> there'd be no difference between description of [1, 2, 3] (i.e. [Int]) and
> Optional([1, 2, 3]) (i.e. [Int]?).
>
> There's also no difference between print(Int(1)) and print(UInt(1)): they
> both output just "1".
Good point.
> I presume that it shouldn't be a problem to change it to use
> CustomStringConvertible instead.
That's true, but you rarely use print directly on the object (at least I
don't), since you usually need a bit more context for it, so you use string
interpolation to add the context - and sometimes you might want the optional
with its current behavior.
There are several approaches this propsal can take:
1) The stdlib will use .description on Optionals which would either return
"nil", or would stringify the value - where .description would be used if the
value is CustomStringConvertible, otherwise, debugPrint would be used as until
now.
This would produce no warnings. print(optional) would still print
Optional(value), but print("\(optional)") would print just value.
Pros: Nothing to be done by the user to migrate current code.
Cons: Still can result in unexpected results since it may return "nil". The
user may be unaware that the value being interpoled is optional. (e.g.
myURL.path, which when nonnil, always starts with "/"). Also, it breaks any
code depending on the current behavior.
2) Deprecate interpolation of Optionals (and nothing else), issue a warning and
offer a fix via either cast to as Any, or by using .description,
.debugDescription or .optionalDescription (or whatever it would be called so
that .description or .debugDescription aren't invoked directly).
Optionally, there could be .valueDescription on Optional which would print
either "nil" or the value as proposed in (1).
Pros: The user has full control over what's printed out.
Cons: Requires some action from the user to migrate current code.
3) Make the solution more robust and introduce the Uninterpolable protocol,
which would generate a warning for interpolation of Optionals and other custom
types.
The Fix-It would offer the same for Optionals as (2). For your custom types, no
Fix-It will be offered - it's up to you.
Pros: You can make custom types generate a warning when interpoled + the Pros
from (2).
Cons: Same as (2).
>
> The above code also hints that there's another odd behavior in the current
> implementation:
>
> struct Foo: CustomStringConvertible, CustomDebugStringConvertible {
> var description: String { return "normal" }
> var debugDescription: String { return "debug" }
> }
>
> let f = Foo()
> let of = Optional(f)
>
> print(f) // "normal": ok
> debugPrint(f) // "debug": ok
> print(of) // "Optional(debug)": unexpected
> debugPrint(of) // "Optional(debug)": ok
>
> --
> Nicola
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution