Cannot use `∅` as a variable name

public protocol Emptiable {
    var isEmpty: Bool { get }
}

public protocol ExpressibleByEmptyLiteral : Emptiable {
    init(emptyLiteral: ())
}

public extension ExpressibleByEmptyLiteral {
    
    static var empty: Self { Self(emptyLiteral: ()) }
    static var ε: Self { Self(emptyLiteral: ()) }
    static var ∅: Self { Self(emptyLiteral: ()) } // Error: expected pattern
}

is parsed as an operator, not an identifier. You can use Ø instead.

1 Like

Once upon a time there was a plan to recategorize characters to put the operator and identifier distinctions on solid footing, instead of the ad-hoc situation we have today.

As I recall, @xwu and I debated extensively how it should be done, and in the end he presented a well-thought-out plan for what characters should be operators.

I know that both the empty set () and the infinity sign () were points of contention, however in the end the discussion petered out and no changes were made.

1 Like

I prefer using '∅' to mark it a variable name instead of an operator.
∅ can still be an operator.

I think there should be a way let any Unicode character appear in a variable name.

Obviously, ∅ is not an operator both in Mathematica and Computer Science, right?

I use an operator way to solve my problem. Same as ... in subscript.

public protocol ExpressibleByEmpty : Emptiable {
    init(_ :Empty)
}

public extension ExpressibleByEmpty {
    
    static var empty: Self { Self(∅) }
    static var ε: Self { Self(∅) }
}

postfix operator ∅
public enum Empty_ {
    
    /// Creates an empty expression.
    ///
    /// The empty operator (`∅`) is valid only within the init of ExpressibleByEmpty.
    postfix public static func ∅ (_: Empty_) {}
}
public typealias Empty = (Empty_) -> ()

Then you can use SomeEmptiable.init(∅) to create an empty instance of SomeEmptiable,
as same as or .empty.

I think there should be a transfer mechanism (or overload) for the assign operator or the init process.
It would be easier to read when assign Empty to SomeEmptiable, just like
let a : SomeEmptiable = ∅

for example:

extension Optional : ExpressibleByEmpty { public init(_ :Empty) { self = nil } }
extension Bool : ExpressibleByEmpty { public init(_ :Empty) { self = false } }

public extension ExpressibleByStringLiteral { init(_: Empty) {  self = ""  } }
extension     String : ExpressibleByEmpty {}

public extension ExpressibleByArrayLiteral { init(_: Empty) {   self = []  } }
extension      Array : ExpressibleByEmpty {}
extension        Set : ExpressibleByEmpty {}
extension OrderedSet : ExpressibleByEmpty {}
extension UnorderedArray : ExpressibleByEmpty {}

public extension ExpressibleByDictionaryLiteral { init(_: Empty) {  self = [:]  }}
extension Dictionary : ExpressibleByEmpty {}

then

let optional: Optional<Int>   = ∅ // equals to `nil`
let bool: Bool                = ∅ // equals to `false`
let string: String            = ∅ // equals to `""`
let array: Array<Int>         = ∅ // equals to `[]`
let set: Set<Int>             = ∅ // equals to `[]`
let dict: Dict<String : Int>  = ∅ // equals to `[:]`

would be better than

let optional: Optional<Int>   = .init(∅) // equals to `nil`
let bool: Bool                = .init(∅) // equals to `false`
let string: String            = .init(∅) // equals to `""`
let array: Array<Int>         = .init(∅) // equals to `[]`
let set: Set<Int>             = .init(∅) // equals to `[]`
let dict: Dict<String : Int>  = .init(∅) // equals to `[:]`

or

let optional: Optional<Int>   = .ε // equals to `nil`
let bool: Bool                = .ε // equals to `false`
let string: String            = .ε // equals to `""`
let array: Array<Int>         = .ε // equals to `[]`
let set: Set<Int>             = .ε // equals to `[]`
let dict: Dict<String : Int>  = .ε // equals to `[:]`

That'd be a little hard to do. IIRC the identifier-operator dichotomy is decided during lexing period; it reads the text and decides right then, right there, without looking around.

Should we have transferring mechanism, we'll need to defer that decision, which would be non-trivial work, or perhaps there's a one-off patchwork that we can use, which may be a little tricky.

1 Like

IIRC the current design is motivated by the ease of parsing by anything that's not the compiler. Discourse forums like this one, GitHub, non-LSP text editors, etc.

It's conceivable to allow some kind of really complex and powerful process for picking with a sigil is an identifier or an operator, but that's not something that would be possible by anything other than the compiler, which diminishes the Swift experience in other realms (such as browsing code online).

1 Like