1

I would like to have a new logical operator. However, when I try to define it as:

def xor (that: Boolean): Boolean = (this || that) && !(this && that)

and then use it, I get following error:

value xor is not a member of Boolean

The xor definition is located in the same class just before the function I'm using it.

What is the right place where the operator definition should be placed?

pogurek
  • 33
  • 5
  • 2
    A question that is of interest to me, is why you thought this would work in the first place? It is clear that your method takes two parameters, yet you are only passing one argument, so even without knowing much about Scala, it is easy to see that this cannot work. As someone who is interested in language design, I am curious which languages you know where it works that way. – Jörg W Mittag Jun 21 '20 at 16:02
  • 1
    @JörgWMittag Nim lets you do that, and I think D does too. Also, type constructors that take 2 parameters can be used in an infix manner, so maybe that's where the OP got that idea? – user Jun 21 '20 at 16:10
  • @JörgWMittag You are right, it was nonsense. I copy pasted different thing. Now it's corrected. – pogurek Jun 21 '20 at 21:00
  • @user In a brilliant way! An extension method to booleans is what I was looking for. I learned about two very nice featuers in scala, i.e. *implicit* and *value class*. Thank you! – pogurek Jun 21 '20 at 21:33
  • @jwvh OK. Done. – pogurek Jun 21 '20 at 22:13

1 Answers1

2

I'm not sure if you know about it, but there is a bitwise XOR operator in Scala already (^), which you'd probably prefer.

To add extension methods to booleans, you can't simply define a function that takes 2 parameters. You'll have to wrap the boolean in an implicit class and define a proper method on that.

implicit class Xorable(private val a: Boolean) extends AnyVal {
  def xor(b: Boolean) = a ^ b
}

and only then can you use it like true xor false. The method you've defined above can only be used as xor(a, b)

Edit: As Luis Miguel Mejía Suárez pointed out

It is usually a good idea to make your implicit classes to be value classes.

The only thing is that you can't have an implicit value class whose parameter is an instance of another value class. Since Booleans are value classes, you'll have to either not use value classes or make an implicit def in this case, but for AnyRef's descendants, you can just add an extends AnyVal to that first implicit class. Actually -

The restriction only apply to user-defined value classes, you can make the implicit class of booleans to be a value class

By the way, you can just do this in Dotty, as far as I know:

def (a: Boolean) xor (b: Boolean) = a ^ b
user
  • 7,435
  • 3
  • 14
  • 44
  • 1
    It is usually a good idea to make your implicit classes to be value classes. – Luis Miguel Mejía Suárez Jun 21 '20 at 15:46
  • 1
    @LuisMiguelMejíaSuárez But you can't make them value classes if the field is also a value class – user Jun 21 '20 at 15:46
  • 1
    True, but that is a weird situation. Still, great clarification. – Luis Miguel Mejía Suárez Jun 21 '20 at 15:53
  • The restriction only apply to user-defined value classes, you can make the implicit class of booleans to be a value class, see [here](https://scastie.scala-lang.org/BalmungSan/Djj6DvwBScOmMqrY6hqwcQ). – Luis Miguel Mejía Suárez Jun 21 '20 at 16:04
  • @LuisMiguelMejíaSuárez Thanks! I'll fix that in my answer – user Jun 21 '20 at 16:06
  • I'm sorry. I made a mistake in the definition. Now it's corrected. However the point stays the same. I haven't heard about the implicit class before. This seems to be the perfect solution for this case. Thanks a lot! – pogurek Jun 21 '20 at 21:14
  • 1
    Guys, you were both right. I haven't heard about value class either. When I google it I found [this article](https://docs.scala-lang.org/overviews/core/value-classes.html#extension-methods) and combination of implicit and value class does the trick. Thanks a lot again! – pogurek Jun 21 '20 at 21:26