Allow regular letters as operator names

You've been told the reason. You don't accept it, and that's OK. You're not required to agree with every decision made about Swift, or even any decision. But your tone is getting increasingly hostile. It's not appropriate for this forum.

Operators in Swift can have different precedence levels, and you can have pre- and post-fix operators, not just infix.

2 Likes

True. You can't invoke operators as functions. That does not negate the fact that you did not do so in your example.

A common tutorial example for reduce is array.reduce(0, +). You wouldn't want the + operator to invoked and its value is passed as a parameter.

I wrote the example off the top of my head, and I got it slightly wrong. Please be civil in your response.

6 Likes

I'm not sure how reflective my use-case is, but I spend a lot of my time reading code (majority?) in GitHub.

I don't spend the majority of my time there, but I certainly do read code in places other than IDEs on a regular basis. Besides GitHub, there's also Slack snippets.

I want to add to this a bit. It also become ambiguous if we even allow mixing the character set. +t would be ambiguous between a prefix + applied to t and an operator +t.

You mean, like this?

(+)(3, 4)

Swift needs you to add parentheses because it's ambiguous whether you're trying to treat + as a function or to apply prefix + to a tuple. For all intents and purposes, operators are functions.

6 Likes

I was hoping that this feature would be used in rare circumstances, like function builders. My intention is not to make a fancy replacement of || to or. Even if it appeared tomorrow and svn's would disable syntax highlighting, I don't think that this would make life of people too much harder. The potential benefit outweighs any other dissent.

You actually can:

prefix operator |><>
prefix func |><> (rval: String = "!") -> String {
	return rval
}

print((|><>)())

It's just quite rare.

You found a valid finding (default arguments in operator functions don't make much sense, since their arity is fixed on a "higher level"), but I really don't understand the conclusions you're trying to draw from this oversight existing.

3 Likes

FWIW, this requires much more than relaxing operator tokenization rules. You'd at least need to be able to access and assign to uninitialized variables, which is something reserved solely to =. And I don't even know how to parse the rest of the line (which one is operator, which one is function call), so it's hard to tell if you need more.

4 Likes

That was definetly not something lying on the surface.

It's the same as array.reduce(0, +) if you think about it :wink:

3 Likes

Worse yet: if you have +example, there's an entire tree of candidate expressions:

  • + (op) example (var)
  • +e (op) xample (var)
  • +ex (op) ample (var)
  • ...
  • + (op) e (op) xample (var)
  • ...
  • + (op) e (op) x (op) a (op) m (op) p (op) le (var)

I'm too decaffeinated to calculate the rough number of them, but I'm guessing at least 2^n (n being the char count of the expression), which is the number of distinct subsets you can draw from a set. It's even more, since each set can be chosen to be an operator or an identifier.

It would certainly require access to the declarations to be able to interpret this without grinding to a halt.

3 Likes

Well, regarding parsing, I think that compiler could start parsing expressions with an assumption that it starts with prefix operator (which should be made with mandatory trailing whitespace), then it could check if expression is followed by an operator and then forward scan to find out if that operator infix or postfix one. Maybe this is something.

Sure, I readily admitted myself that it's quite see to see an operator be used like that, at least explicitly. As Lantua states, that's precisely what happens when you call array.reduce(0, +), it's just that the access of the operator + happens in one area, and the calling of it (with () and 2 arguments) is tucked behind the implementation of reduce().

This thread is kind of unpleasant.

This was proposed in the past, and rejected for good reasons (at least IMO, but you can feel free to disagree). You were cited some of the many discussion on this topic, and it's clear that you haven't caught up on all that was already said, so this is just a pointless rehashing of existing conversations.

Further, you assert statements like "well this isn't possible" (implication, swift bad), get shown that it is possible, and respond with "well that was obscure" (implication, swift still bad). Not my fault you haven't taken the time to more intimately familiarize yourself with the operator feature of the language :man_shrugging:

And what gets me the most is that because you're not sufficiently informed on this topic, your proposals have consequences you don't understand. That's fine, but in response you double down and say "well some of you will have to die, but that's a sacrifice I'm willing to make".

No thanks. Don't mess with my code highlighting, please. At least acknowledge the trade off, that it exists, and that others (who might have different values/expectations of the programming language) can reasonably disagree that the trade-off is worth making.

And for what it's worth, I am interested in more features to support better DSLs. But it's a really hard set of things to do, particularly in a statically typed language. If everything is untyped, unchecked method calls, then Ruby's demonstrates it's possible to make really rich embedded DSLs. But Swift is operating under a lot more constraints in order to preserve rich type checking, definite initialization, etc. which makes it significantly harder. As Lantua pointed out, you desired syntax would require much more than just changes to the identifier/operator character partitioning. Stuff I'd be open to potentially, but at least learn enough to appreciate the complexity of the things you're non-nonchalantly proposing.

5 Likes

There is a requirement for pre-fix operators to be adjacent to their operand. This to allow the following to parse correctly:

let a = 1 + -1
let b = 1 + +1

If operator names could contain the same characters as identifiers, it would be impossible to correctly parse @AlexanderM's example.

2 Likes

I spawned this thread under discussion and expected to get to know whether there are something that is impossible at the fundamental level. It is clear that something can be done. If someone just showed exact example of why it is ambiguous and this cannot be implemented, I would concede. None of such examples was given.

Probably you noticed the thing called function builders getting into language, and this change to operators would allow to make better user-visible api, I state once again.

Also I curios about where did you familiarize yourself with operators?

An explosion of search space doesn't seem to faze you. Being optimistic is a good attitude, though it'd hard-pressed to say that we can ignore it.

That's still at least n^2. It's still not great since Swift does encourage naming things properly, makeing the name relative long at times. It will also fail to parse +a+b which is a valid Swift today (for Int). There's also current requirement that prefix/postfix has no space as @Avi mentioned, which seems to be incompatible with what you propose.

You can start by reading the linked thread. That's good start for everyone. You shouldn't bump it though, it was in the era of mailing list and is quite old.

3 Likes

More I fazed that it does not interpret it as (prefix) (operand) (prefix) (operand).

It exists already since a bunch of these operators are overloaded.

It doesn't. Scan line, identify +, it is obviously prefix, scan to next token, argument found, scan next, maybe infix or prefix, scan forward, ok operand, thus
((prefix a) infix b)

How do you know a is the operand and not part of the operator name? What if there's both an operator with that name and an identifier in scope?

2 Likes

You could check against name in operator declaration, which could be collected at early stages of parsing.