Proposal: extend Optional-specific syntax to arbitrary types with CustomOptionalConvertible


(Krzysztof Siejkowski) #1

Hi,

# Introduction

I'd like to propose a non-invasive way of extending the funtionality of `if let` conditional binding (and potencially other Optional-related language constructs) by introducing `CustomOptionalConvertible` protocol. The idea is basically the same as with `CustomStringConvertible` protocol used to provide string interpolation or with `~=` operator used in `switch` statement pattern matching. I believe it's going to simplity and unify the use of the Optional-related family of Swift syntax constructs for custom types.

The proposal is in a draft stage right now, I'll clear it up if it proves worth to be pull-requested.

# Motivation

One of the Swift features that are core to it's safety and readability are Optionals. They're important enough to be given special place in the language syntax. Special operators like `?`, `!` or `??`, special casting keywords like `as?`, special conditional binding `if let`. The Optionals, however, might be also seen as a member of larger family of constructs: call them monads, boxes, value containers, computational context bearers. One example of those would be a very similar type going by the name of Either, Try or Result. It can be seen as an Optional that carries some additional information about the reason why the value is absent. That information is not always of our interest and in those cases conditional binding for Either type makes a lot of sense. However, the `if let` syntax is currently exclusively working only for optionals.

# Proposed solution

While I'd love to see Swift introducing a powerful construct similar to Haskell's `do-notation` or Scala's `for-comprehension`, I believe it'd require a significant invasive change in the language implementation (and, possibly, vision). Therefore the proposed solutions is much more humble. Let's introduce the `CustomOptionalConvertible` protocol with signature:

protocol CustomOptionalConvertible {
	typealias Wrapped
	public var optional: Optional<Wrapped> { get }
}

Such a protocol will provide a way for an arbitrary type to convert to the Optional. All the types implementing this protocol could then be used in conditional binding syntax without explicit declaration of conversion. I do not propose the introduction of general implicit conversion construct, just a special case. The same as `CustomStringConvertible` is a special case of allowing the value to express itself in the string interpolation.`CustomOptionalConvertible` will allow the author of an arbitratry type to integrate with Swift syntax:

enum Either<Value> {
	case Left(ErrorType)
	case Right(Value)
}

extension Either : CustomOptionalConvertible {
	typealias Wrapped = Value
	public var optional: Optional<Value> {
		get {
			switch (self) {
			case .Left(_): return .None
			case .Right(let value): return .Some(value)
			}
		}
	} 
}

func foo(either: Either<String>) -> String {
	if let string = either {
		return string
	} else {
		return "No value"
	}
}

There is already a similar mechanism available in the context of pattern matching: `~=` operator.

# Impact on the language

While I cannot say much about the impact on the compiler, I believe the introduction will bring no breaking change to the Swift language itself. All the places that are currently requiring Optionals will still require Optionals.

For the language users it'll make it easier to integrate the constructs used in the program with the native syntax, making them easier to use and read. Current solution, namely:

func foo(either: Either<String>) -> String {
	if let string = either.optional {
		return string
	} else {
		return "No value"
	}
}

is introducing unnecessary noise in the otherwise neat syntax. The problem escalates when `if let` cascade is used:

if let string = eitherString.optional
           int = eitherInt.optional
           array = eitherArray.optional 
// ...

# Alternatives considered

The equivalent of Haskell’s `do-notation`. It’s a powerful construct (some say even too powerful, see https://wiki.haskell.org/Do_notation_considered_harmful). However, I can’t imagine it without significant changes to the language syntax (`if let` should return value) and vision (I believe that Optional are syntactic unicorns by design).

All the best,
Krzysztof


(Lily Ballard) #2

I agree. The motivation of this proposal is laudable, but I'm not sure it actually gains anything over just defining a property of optional type on the type in question. For example, with your Either enum, you might have:

var left: ErrorType? var right: Value?

This requires no language changes and allows the use of if-let and
optional chaining. It also allows you to expose your different variants
as optional, instead of assuming that only one variant is special.

-Kevin Ballard

···

On Mon, Dec 7, 2015, at 01:38 PM, Paul Cantrell via swift-evolution wrote:

I like the sentiment of this proposal, but I’m not sure it provides
clear value. We already have a generalized version of “if let” in the
form of “if case”:

func foo(either: Either<String>) -> String { if case .Right(let
string) = either { return string } else { return "No
value" } }

This works with cascades just fine:

if case .Right(let string0) = either0, .Right(let string1)
= either1, .Right(let string2) = either2 {

Leaving aside that Swift’s “if case” syntax is a bit clumsy and hard
to remember at first, does a CustomOptionalConvertible really grant
additional benefit in terms of either safety or readability?

Cheers,

Paul

On Dec 7, 2015, at 2:58 PM, krzysztof@siejkowski.net via swift- >> evolution <swift-evolution@swift.org> wrote:

Hi,

# Introduction

I'd like to propose a non-invasive way of extending the funtionality
of `if let` conditional binding (and potencially other Optional-
related language constructs) by introducing
`CustomOptionalConvertible` protocol. The idea is basically the same
as with `CustomStringConvertible` protocol used to provide string
interpolation or with `~=` operator used in `switch` statement
pattern matching. I believe it's going to simplity and unify the
use of the Optional-related family of Swift syntax constructs for
custom types.

The proposal is in a draft stage right now, I'll clear it up if it
proves worth to be pull-requested.

# Motivation

One of the Swift features that are core to it's safety and
readability are Optionals. They're important enough to be given
special place in the language syntax. Special operators like `?`, `!`
or `??`, special casting keywords like `as?`, special conditional
binding `if let`. The Optionals, however, might be also seen as a
member of larger family of constructs: call them monads, boxes, value
containers, computational context bearers. One example of those would
be a very similar type going by the name of Either, Try or Result.
It can be seen as an Optional that carries some additional
information about the reason why the value is absent. That
information is not always of our interest and in those cases
conditional binding for Either type makes a lot of sense. However,
the `if let` syntax is currently exclusively working only for
optionals.

# Proposed solution

While I'd love to see Swift introducing a powerful construct similar
to Haskell's `do-notation` or Scala's `for-comprehension`, I believe
it'd require a significant invasive change in the language
implementation (and, possibly, vision). Therefore the proposed
solutions is much more humble. Let's introduce the
`CustomOptionalConvertible` protocol with signature:

optional: Optional<Wrapped> { get } } ```

Such a protocol will provide a way for an arbitrary type to convert
to the Optional. All the types implementing this protocol could then
be used in conditional binding syntax without explicit declaration of
conversion. I do not propose the introduction of general implicit
conversion construct, just a special case. The same as
`CustomStringConvertible` is a special case of allowing the value to
express itself in the string
interpolation.`CustomOptionalConvertible` will allow the author of an
arbitratry type to integrate with Swift syntax:

``` enum Either<Value> { case Left(ErrorType) case Right(Value) }

extension Either : CustomOptionalConvertible \{ typealias Wrapped =
Value public var optional: Optional&lt;Value&gt; \{ get \{ switch \(self\) \{
case \.Left\(\_\): return \.None case \.Right\(let value\): return
\.Some\(value\) \} \} \} \}

func foo\(either: Either&lt;String&gt;\) \-&gt; String \{ if let string = either \{
return string \} else \{ return &quot;No value&quot; \} \} \`\`\`

There is already a similar mechanism available in the context of
pattern matching: \`\~=\` operator\.

\# Impact on the language

While I cannot say much about the impact on the compiler, I believe
the introduction will bring no breaking change to the Swift language
itself\. All the places that are currently requiring Optionals will
still require Optionals\.

For the language users it&#39;ll make it easier to integrate the
constructs used in the program with the native syntax, making them
easier to use and read\. Current solution, namely: \`\`\` func
foo\(either: Either&lt;String&gt;\) \-&gt; String \{ if let string =
either\.optional \{ return string \} else \{ return &quot;No value&quot; \} \} \`\`\` is
introducing unnecessary noise in the otherwise neat syntax\. The
problem escalates when \`if let\` cascade is used: \`\`\` if let string =
eitherString\.optional           int = eitherInt\.optional
array = eitherArray\.optional // \.\.\. \`\`\`

\# Alternatives considered

The equivalent of Haskell’s \`do\-notation\`\. It’s a powerful construct
\(some say even too powerful, see
https://wiki.haskell.org/Do_notation_considered_harmful\)\. However, I
can’t imagine it without significant changes to the language syntax
\(\`if let\` should return value\) and vision \(I believe that Optional
are syntactic unicorns by design\)\.

All the best, Krzysztof
 \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
swift\-evolution mailing list swift\-evolution@swift\.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_________________________________________________
swift-evolution mailing list swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Paul Cantrell) #3

I like the sentiment of this proposal, but I’m not sure it provides clear value. We already have a generalized version of “if let” in the form of “if case”:

    func foo(either: Either<String>) -> String {
        if case .Right(let string) = either {
            return string
        } else {
            return "No value"
        }
    }

This works with cascades just fine:

    if case .Right(let string0) = either0,
            .Right(let string1) = either1,
            .Right(let string2) = either2 {

Leaving aside that Swift’s “if case” syntax is a bit clumsy and hard to remember at first, does a CustomOptionalConvertible really grant additional benefit in terms of either safety or readability?

Cheers,

Paul

···

On Dec 7, 2015, at 2:58 PM, krzysztof@siejkowski.net via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

# Introduction

I'd like to propose a non-invasive way of extending the funtionality of `if let` conditional binding (and potencially other Optional-related language constructs) by introducing `CustomOptionalConvertible` protocol. The idea is basically the same as with `CustomStringConvertible` protocol used to provide string interpolation or with `~=` operator used in `switch` statement pattern matching. I believe it's going to simplity and unify the use of the Optional-related family of Swift syntax constructs for custom types.

The proposal is in a draft stage right now, I'll clear it up if it proves worth to be pull-requested.

# Motivation

One of the Swift features that are core to it's safety and readability are Optionals. They're important enough to be given special place in the language syntax. Special operators like `?`, `!` or `??`, special casting keywords like `as?`, special conditional binding `if let`. The Optionals, however, might be also seen as a member of larger family of constructs: call them monads, boxes, value containers, computational context bearers. One example of those would be a very similar type going by the name of Either, Try or Result. It can be seen as an Optional that carries some additional information about the reason why the value is absent. That information is not always of our interest and in those cases conditional binding for Either type makes a lot of sense. However, the `if let` syntax is currently exclusively working only for optionals.

# Proposed solution

While I'd love to see Swift introducing a powerful construct similar to Haskell's `do-notation` or Scala's `for-comprehension`, I believe it'd require a significant invasive change in the language implementation (and, possibly, vision). Therefore the proposed solutions is much more humble. Let's introduce the `CustomOptionalConvertible` protocol with signature:

protocol CustomOptionalConvertible {
	typealias Wrapped
	public var optional: Optional<Wrapped> { get }
}

Such a protocol will provide a way for an arbitrary type to convert to the Optional. All the types implementing this protocol could then be used in conditional binding syntax without explicit declaration of conversion. I do not propose the introduction of general implicit conversion construct, just a special case. The same as `CustomStringConvertible` is a special case of allowing the value to express itself in the string interpolation.`CustomOptionalConvertible` will allow the author of an arbitratry type to integrate with Swift syntax:

enum Either<Value> {
	case Left(ErrorType)
	case Right(Value)
}

extension Either : CustomOptionalConvertible {
	typealias Wrapped = Value
	public var optional: Optional<Value> {
		get {
			switch (self) {
			case .Left(_): return .None
			case .Right(let value): return .Some(value)
			}
		}
	} 
}

func foo(either: Either<String>) -> String {
	if let string = either {
		return string
	} else {
		return "No value"
	}
}

There is already a similar mechanism available in the context of pattern matching: `~=` operator.

# Impact on the language

While I cannot say much about the impact on the compiler, I believe the introduction will bring no breaking change to the Swift language itself. All the places that are currently requiring Optionals will still require Optionals.

For the language users it'll make it easier to integrate the constructs used in the program with the native syntax, making them easier to use and read. Current solution, namely:

func foo(either: Either<String>) -> String {
	if let string = either.optional {
		return string
	} else {
		return "No value"
	}
}

is introducing unnecessary noise in the otherwise neat syntax. The problem escalates when `if let` cascade is used:

if let string = eitherString.optional
           int = eitherInt.optional
           array = eitherArray.optional 
// ...

# Alternatives considered

The equivalent of Haskell’s `do-notation`. It’s a powerful construct (some say even too powerful, see https://wiki.haskell.org/Do_notation_considered_harmful). However, I can’t imagine it without significant changes to the language syntax (`if let` should return value) and vision (I believe that Optional are syntactic unicorns by design).

All the best,
Krzysztof
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #4

For what it's worth, I filed a radar for a protocol along these lines epic the early days OS Swift, but took a slightly different approach. It looked something like this:

protocol PossibleValueType {
     typealias Value
    var hasValue: Bool { get }
    var value: Value // implementations call fatalError or similar if hasValue is false
}

Rather than returning an Optional that wraps the value we allow presence or absence of value to be detected and if a value is present we allow it to be extracted.

Matthew

···

Sent from my iPad

On Dec 7, 2015, at 3:38 PM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

I like the sentiment of this proposal, but I’m not sure it provides clear value. We already have a generalized version of “if let” in the form of “if case”:

    func foo(either: Either<String>) -> String {
        if case .Right(let string) = either {
            return string
        } else {
            return "No value"
        }
    }

This works with cascades just fine:

    if case .Right(let string0) = either0,
            .Right(let string1) = either1,
            .Right(let string2) = either2 {

Leaving aside that Swift’s “if case” syntax is a bit clumsy and hard to remember at first, does a CustomOptionalConvertible really grant additional benefit in terms of either safety or readability?

Cheers,

Paul

On Dec 7, 2015, at 2:58 PM, krzysztof@siejkowski.net via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

# Introduction

I'd like to propose a non-invasive way of extending the funtionality of `if let` conditional binding (and potencially other Optional-related language constructs) by introducing `CustomOptionalConvertible` protocol. The idea is basically the same as with `CustomStringConvertible` protocol used to provide string interpolation or with `~=` operator used in `switch` statement pattern matching. I believe it's going to simplity and unify the use of the Optional-related family of Swift syntax constructs for custom types.

The proposal is in a draft stage right now, I'll clear it up if it proves worth to be pull-requested.

# Motivation

One of the Swift features that are core to it's safety and readability are Optionals. They're important enough to be given special place in the language syntax. Special operators like `?`, `!` or `??`, special casting keywords like `as?`, special conditional binding `if let`. The Optionals, however, might be also seen as a member of larger family of constructs: call them monads, boxes, value containers, computational context bearers. One example of those would be a very similar type going by the name of Either, Try or Result. It can be seen as an Optional that carries some additional information about the reason why the value is absent. That information is not always of our interest and in those cases conditional binding for Either type makes a lot of sense. However, the `if let` syntax is currently exclusively working only for optionals.

# Proposed solution

While I'd love to see Swift introducing a powerful construct similar to Haskell's `do-notation` or Scala's `for-comprehension`, I believe it'd require a significant invasive change in the language implementation (and, possibly, vision). Therefore the proposed solutions is much more humble. Let's introduce the `CustomOptionalConvertible` protocol with signature:

protocol CustomOptionalConvertible {
	typealias Wrapped
	public var optional: Optional<Wrapped> { get }
}

Such a protocol will provide a way for an arbitrary type to convert to the Optional. All the types implementing this protocol could then be used in conditional binding syntax without explicit declaration of conversion. I do not propose the introduction of general implicit conversion construct, just a special case. The same as `CustomStringConvertible` is a special case of allowing the value to express itself in the string interpolation.`CustomOptionalConvertible` will allow the author of an arbitratry type to integrate with Swift syntax:

enum Either<Value> {
	case Left(ErrorType)
	case Right(Value)
}

extension Either : CustomOptionalConvertible {
	typealias Wrapped = Value
	public var optional: Optional<Value> {
		get {
			switch (self) {
			case .Left(_): return .None
			case .Right(let value): return .Some(value)
			}
		}
	} 
}

func foo(either: Either<String>) -> String {
	if let string = either {
		return string
	} else {
		return "No value"
	}
}

There is already a similar mechanism available in the context of pattern matching: `~=` operator.

# Impact on the language

While I cannot say much about the impact on the compiler, I believe the introduction will bring no breaking change to the Swift language itself. All the places that are currently requiring Optionals will still require Optionals.

For the language users it'll make it easier to integrate the constructs used in the program with the native syntax, making them easier to use and read. Current solution, namely:

func foo(either: Either<String>) -> String {
	if let string = either.optional {
		return string
	} else {
		return "No value"
	}
}

is introducing unnecessary noise in the otherwise neat syntax. The problem escalates when `if let` cascade is used:

if let string = eitherString.optional
           int = eitherInt.optional
           array = eitherArray.optional 
// ...

# Alternatives considered

The equivalent of Haskell’s `do-notation`. It’s a powerful construct (some say even too powerful, see https://wiki.haskell.org/Do_notation_considered_harmful). However, I can’t imagine it without significant changes to the language syntax (`if let` should return value) and vision (I believe that Optional are syntactic unicorns by design).

All the best,
Krzysztof
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Krzysztof Siejkowski) #5

First, thanks for the feedback! By no means is a `CustomOptionalConvertible` an essential addition to Swift, I just think it’s a low-hanging fruit in terms of unifying the usage of `if let` syntax.

The main idea would be to enable `if let` for predefined types (for example, provided by a third-party framework) without exposing their inner structure. I think it’s beneficial in terms of readability and clarity. Of course it might turn to be an unpopular opinion :slight_smile:

Addressing Paul’s concerns: there are two drawback that I can see:

1) As far as I know, `if case` can be used only with enums (I'd love to proven wrong)
2) It explicitly cites the inner structure of the type in the conditional binding. In the particular example - the existence of .Right cause and how many associated values it has.

Addressing Kevin’s concerns: I’ve already used a similar solution, namely:

if let string = eitherString\.optional

which is of course just a renaming of

if let string = eitherString\.right

There’s nothing wrong with that solution functionality-wise, I just find the ability to use

if let string = someValue

consistently for all the types that the idea of conditional binding applies to more consistent and more readable. Please consider the conditional binding cascade for multiple types:

if let string0 = eitherString\.right
        string1 = optionalString
        string2 = futureString\.get \{

versus

if let string0 = possibleString0
        string1 = possibleString1
        string2 = possileString2 \{

where no knowledge about the inner structure of the possibleStringN values is exposed - the only thing that matters here is the applicability of conditional binding.

All the best,
Krzysztof

···

From: Kevin Ballard via swift-evolution <swift-evolution@swift.org>
Reply: Kevin Ballard <kevin@sb.org>
Date: December 7, 2015 at 10:47:23 PM
To: swift-evolution@swift.org <swift-evolution@swift.org>
Subject: Re: [swift-evolution] Proposal: extend Optional-specific syntax to arbitrary types with CustomOptionalConvertible

I agree. The motivation of this proposal is laudable, but I'm not sure it actually gains anything over just defining a property of optional type on the type in question. For example, with your Either enum, you might have:

var left: ErrorType?
var right: Value?

This requires no language changes and allows the use of if-let and optional chaining. It also allows you to expose your different variants as optional, instead of assuming that only one variant is special.

-Kevin Ballard

On Mon, Dec 7, 2015, at 01:38 PM, Paul Cantrell via swift-evolution wrote:
I like the sentiment of this proposal, but I’m not sure it provides clear value. We already have a generalized version of “if let” in the form of “if case”:

func foo(either: Either<String>) -> String {
if case .Right(let string) = either {
return string
} else {
return "No value"
}
}

This works with cascades just fine:

if case .Right(let string0) = either0,
.Right(let string1) = either1,
.Right(let string2) = either2 {

Leaving aside that Swift’s “if case” syntax is a bit clumsy and hard to remember at first, does a CustomOptionalConvertible really grant additional benefit in terms of either safety or readability?

Cheers,

Paul

On Dec 7, 2015, at 2:58 PM, krzysztof@siejkowski.net via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

# Introduction

I'd like to propose a non-invasive way of extending the funtionality of `if let` conditional binding (and potencially other Optional-related language constructs) by introducing `CustomOptionalConvertible` protocol. The idea is basically the same as with `CustomStringConvertible` protocol used to provide string interpolation or with `~=` operator used in `switch` statement pattern matching. I believe it's going to simplity and unify the use of the Optional-related family of Swift syntax constructs for custom types.

The proposal is in a draft stage right now, I'll clear it up if it proves worth to be pull-requested.

# Motivation

One of the Swift features that are core to it's safety and readability are Optionals. They're important enough to be given special place in the language syntax. Special operators like `?`, `!` or `??`, special casting keywords like `as?`, special conditional binding `if let`. The Optionals, however, might be also seen as a member of larger family of constructs: call them monads, boxes, value containers, computational context bearers. One example of those would be a very similar type going by the name of Either, Try or Result. It can be seen as an Optional that carries some additional information about the reason why the value is absent. That information is not always of our interest and in those cases conditional binding for Either type makes a lot of sense. However, the `if let` syntax is currently exclusively working only for optionals.

# Proposed solution

While I'd love to see Swift introducing a powerful construct similar to Haskell's `do-notation` or Scala's `for-comprehension`, I believe it'd require a significant invasive change in the language implementation (and, possibly, vision). Therefore the proposed solutions is much more humble. Let's introduce the `CustomOptionalConvertible` protocol with signature:

protocol CustomOptionalConvertible {
typealias Wrapped
public var optional: Optional<Wrapped> { get }
}

Such a protocol will provide a way for an arbitrary type to convert to the Optional. All the types implementing this protocol could then be used in conditional binding syntax without explicit declaration of conversion. I do not propose the introduction of general implicit conversion construct, just a special case. The same as `CustomStringConvertible` is a special case of allowing the value to express itself in the string interpolation.`CustomOptionalConvertible` will allow the author of an arbitratry type to integrate with Swift syntax:

enum Either<Value> {
case Left(ErrorType)
case Right(Value)
}
 
extension Either : CustomOptionalConvertible {
typealias Wrapped = Value
public var optional: Optional<Value> {
get {
switch (self) {
case .Left(_): return .None
case .Right(let value): return .Some(value)
}
}
} 
}
 
func foo(either: Either<String>) -> String {
if let string = either {
return string
} else {
return "No value"
}
}

There is already a similar mechanism available in the context of pattern matching: `~=` operator.

# Impact on the language

While I cannot say much about the impact on the compiler, I believe the introduction will bring no breaking change to the Swift language itself. All the places that are currently requiring Optionals will still require Optionals.

For the language users it'll make it easier to integrate the constructs used in the program with the native syntax, making them easier to use and read. Current solution, namely:

func foo(either: Either<String>) -> String {
if let string = either.optional {
return string
} else {
return "No value"
}
}

is introducing unnecessary noise in the otherwise neat syntax. The problem escalates when `if let` cascade is used:

if let string = eitherString.optional
           int = eitherInt.optional
           array = eitherArray.optional 
// ...

# Alternatives considered

The equivalent of Haskell’s `do-notation`. It’s a powerful construct (some say even too powerful, seehttps://wiki.haskell.org/Do_notation_considered_harmful). However, I can’t imagine it without significant changes to the language syntax (`if let` should return value) and vision (I believe that Optional are syntactic unicorns by design).

All the best,
Krzysztof
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Krzysztof Siejkowski) #6

Was it a part of your idea to allow the `PossibleValueType` to be used in Optional-only syntax constructs like conditional binding? If so, do you see any advantages of such solution over `CustomOptionalConvertible`?

Cheers,
Krzysztof

···

On 8 December 2015 at 04:46:55, Matthew Johnson (matthew@anandabits.com) wrote:

For what it's worth, I filed a radar for a protocol along these lines epic the early days OS Swift, but took a slightly different approach. It looked something like this:

protocol PossibleValueType {
typealias Value
var hasValue: Bool { get }
var value: Value // implementations call fatalError or similar if hasValue is false
}

Rather than returning an Optional that wraps the value we allow presence or absence of value to be detected and if a value is present we allow it to be extracted.

Matthew

Sent from my iPad

On Dec 7, 2015, at 3:38 PM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

I like the sentiment of this proposal, but I’m not sure it provides clear value. We already have a generalized version of “if let” in the form of “if case”:

func foo\(either: Either&lt;String&gt;\) \-&gt; String \{
    if case \.Right\(let string\) = either \{
        return string
    \} else \{
        return &quot;No value&quot;
    \}
\}

This works with cascades just fine:

if case \.Right\(let string0\) = either0,
        \.Right\(let string1\) = either1,
        \.Right\(let string2\) = either2 \{

Leaving aside that Swift’s “if case” syntax is a bit clumsy and hard to remember at first, does a CustomOptionalConvertible really grant additional benefit in terms of either safety or readability?

Cheers,

Paul

On Dec 7, 2015, at 2:58 PM, krzysztof@siejkowski.net via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

# Introduction

I'd like to propose a non-invasive way of extending the funtionality of `if let` conditional binding (and potencially other Optional-related language constructs) by introducing `CustomOptionalConvertible` protocol. The idea is basically the same as with `CustomStringConvertible` protocol used to provide string interpolation or with `~=` operator used in `switch` statement pattern matching. I believe it's going to simplity and unify the use of the Optional-related family of Swift syntax constructs for custom types.

The proposal is in a draft stage right now, I'll clear it up if it proves worth to be pull-requested.

# Motivation

One of the Swift features that are core to it's safety and readability are Optionals. They're important enough to be given special place in the language syntax. Special operators like `?`, `!` or `??`, special casting keywords like `as?`, special conditional binding `if let`. The Optionals, however, might be also seen as a member of larger family of constructs: call them monads, boxes, value containers, computational context bearers. One example of those would be a very similar type going by the name of Either, Try or Result. It can be seen as an Optional that carries some additional information about the reason why the value is absent. That information is not always of our interest and in those cases conditional binding for Either type makes a lot of sense. However, the `if let` syntax is currently exclusively working only for optionals.

# Proposed solution

While I'd love to see Swift introducing a powerful construct similar to Haskell's `do-notation` or Scala's `for-comprehension`, I believe it'd require a significant invasive change in the language implementation (and, possibly, vision). Therefore the proposed solutions is much more humble. Let's introduce the `CustomOptionalConvertible` protocol with signature:

protocol CustomOptionalConvertible {
typealias Wrapped
public var optional: Optional<Wrapped> { get }
}

Such a protocol will provide a way for an arbitrary type to convert to the Optional. All the types implementing this protocol could then be used in conditional binding syntax without explicit declaration of conversion. I do not propose the introduction of general implicit conversion construct, just a special case. The same as `CustomStringConvertible` is a special case of allowing the value to express itself in the string interpolation.`CustomOptionalConvertible` will allow the author of an arbitratry type to integrate with Swift syntax:

enum Either<Value> {
case Left(ErrorType)
case Right(Value)
}

extension Either : CustomOptionalConvertible {
typealias Wrapped = Value
public var optional: Optional<Value> {
get {
switch (self) {
case .Left(_): return .None
case .Right(let value): return .Some(value)
}
}
} 
}

func foo(either: Either<String>) -> String {
if let string = either {
return string
} else {
return "No value"
}
}

There is already a similar mechanism available in the context of pattern matching: `~=` operator.

# Impact on the language

While I cannot say much about the impact on the compiler, I believe the introduction will bring no breaking change to the Swift language itself. All the places that are currently requiring Optionals will still require Optionals.

For the language users it'll make it easier to integrate the constructs used in the program with the native syntax, making them easier to use and read. Current solution, namely:

func foo(either: Either<String>) -> String {
if let string = either.optional {
return string
} else {
return "No value"
}
}

is introducing unnecessary noise in the otherwise neat syntax. The problem escalates when `if let` cascade is used:

if let string = eitherString.optional
           int = eitherInt.optional
           array = eitherArray.optional 
// ...

# Alternatives considered

The equivalent of Haskell’s `do-notation`. It’s a powerful construct (some say even too powerful, see https://wiki.haskell.org/Do_notation_considered_harmful). However, I can’t imagine it without significant changes to the language syntax (`if let` should return value) and vision (I believe that Optional are syntactic unicorns by design).

All the best,
Krzysztof
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #7

Was it a part of your idea to allow the `PossibleValueType` to be used in Optional-only syntax constructs like conditional binding? If so, do you see any advantages of such solution over `CustomOptionalConvertible`?

Yes that was the point of it.

The biggest difference is probably avoiding the need to wrap the value in an Optional. I'm not sure whether that would be a significant advantage or not but I believe it would avoid some copying and reference counting operations.

Matthew