Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No ability to overload unary logial not operator #18279

Open
dlangBugzillaToGithub opened this issue Nov 3, 2024 · 7 comments
Open

No ability to overload unary logial not operator #18279

dlangBugzillaToGithub opened this issue Nov 3, 2024 · 7 comments

Comments

@dlangBugzillaToGithub
Copy link

Mai Lapyst reported this on 2024-11-03T02:04:48Z

Transferred from https://issues.dlang.org/show_bug.cgi?id=24842

CC List

  • Dominikus Dittes Scherkl

Description

Dlang has wide range support for overloading nearly all operators the language supports. However, I'm missing support for the unary logical not operator.

Usecases are implementation of (feature-)flags, or my current use-case, notation of if an certain format is allowed or not for serialization / processing. Essentially all datastuctures that are logically negateable would benefit of the ability to overload the logical not operator.

Example:
```d
struct FormatId {
    string id;
    bool allowed = true;

    this(string id) {
        this.id = id;
    }

    private this(string id, bool allowed) {
        this.id = id;
        this.allowed = allowed;
    }

    auto opUnary(string op)() if (op == "!") {
        return FormatId(this.id, !this.allowed);
    }
}

unittest {
  auto f1 = FormatId("test");
  assert(f1.allowed == true);
  auto f2 = !f1;
  assert(f1.allowed == true);
  assert(f2.allowed == false);
}
```
@dlangBugzillaToGithub
Copy link
Author

dominikus commented on 2024-11-03T10:18:27Z

"!" is overwritten using the opCast!bool() operator (it's a cast to the other boolean value). This is like opCmp() overwrites all comparison operators.

@dlangBugzillaToGithub
Copy link
Author

dominikus commented on 2024-11-03T10:27:42Z

See language reference 21.2.1 "Boolean Operations"

@dlangBugzillaToGithub
Copy link
Author

info commented on 2024-11-04T22:29:53Z

> See language reference 21.2.1 "Boolean Operations"
I'm well aware of this section of the specs, but it's not an viable substitude for what I'm propsing.

It's also not anywhere near the ability of overloading the `!` operator, because this section uses a trick by simple converting it to a plain bool beforehand via `opCast!(bool)()`. But when using this, any other information is lost forever.

Like in the example I send with the inital comment; it contains additional information which I cannot retrieve after the conversion to an plain boolean value; but I **need** to somehow keep it since the type **itself** is boolish (which means has an two-value state).

Again, what I want is to create an struct `FormatId("abc", true)` which when negated using the d-native `!`-operator turns into an instance of `FormatId("abc", false)`. This is simply not possible at the moment.

I can respect if this is not an usecase that dlang wishes to support, but I feel the language then would limit itself unnessearily.

@dlangBugzillaToGithub
Copy link
Author

dominikus commented on 2024-11-04T23:37:50Z

This is the reason some operators are convoluted - to prevent someone from shooting himself in the feat by implementing them inconsistently.

Everybody expects the ! operator to return a boolean, not some "boolish" object.
This is because it is used in conditions, where nothing else then the logical value is needed. Any other information is not evaluated in a condition, so why keep it?

If you want something different, write some other member function which returns something "not-ish".

@dlangBugzillaToGithub
Copy link
Author

info commented on 2024-11-05T00:01:25Z

Thats hardly an reason imho. Because if we use that logic, everybody would expect `+`  to only work on numerical values since it means "addition", jet it's perfectly fine to do things like this:

```d
struct A {}
struct B {}
struct C {
   B opBinary(string op : "+")(A rhs){
     return B();
   }
}

void main() {
  C c;
  B b = c + A();
}
```

I would argue that this produces the same "shooting yourself in the foot" as an overloadable ! operator would.

@dlangBugzillaToGithub
Copy link
Author

dominikus commented on 2024-11-05T11:49:36Z

(In reply to Mai Lapyst from comment #5)
> [...] if we use that logic, everybody would
> expect `+`  to only work on numerical values since it means "addition"
Yes, that would be desirable, but it's much harder to enforce, as it is not easy to detect if something is "numeric" or not. At least D has the "~" operator, so that is no more necessary to convolute addition and concatenation.

I think D found a good compromise by only forbidding things that are confusing and at the same time really not necessary. If you need to "negate" some object, why not overload the unary operator "-" or "~"? They are much more commonly understood to produce some kind of inverse.

If your usecase is only that you like to write "!" instead of something else, no matter how confusing that is for the reader of your code, I fear this will not convince anybody to add such a "feature".

@dlangBugzillaToGithub
Copy link
Author

info commented on 2024-11-06T00:56:02Z

> Yes, that would be desirable, but it's much harder to enforce, as it is not easy to detect if something is "numeric" or not. At least D has the "~" operator, so that is no more necessary to convolute addition and concatenation.

Sure it easy, after all, dlang has both the `std.traits.isNumeric` and `std.traits.isScalar` templates that can detect numerical / scalar values, which would be the only types one would expect `+` to work on anyway.

> If you need to "negate" some object, why not overload the unary operator "-" or "~"?
> ...
> If your usecase is only that you like to write "!" instead of something else ...

My usecase is that i find writing `-` (which is an arithmetic inverse) and `~` (which is both an bit-wise inverse AND an concatination in dlang), much more confusing to read when an boolish, logical negation is that what is wanted & being done in-code.

I would also argue that it's more commonly understood that `!` means logical, boolish inverse across languages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant