> 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
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to