Is there an easy way to convert a Boolean to an Integer?
Asked Answered
K

7

47

I am new to Scala and I am finding the need to convert a Boolean value to an Integer. I know I can use something like if (x) 1 else 0 but I would like to know if there is a preferred method, or something built into the language (i.e. toInt()).

Kliber answered 13/4, 2010 at 22:47 Comment(2)
Without more context, I would say that it not really a good practice. Booleans are not integers, I won't implicitly convert from one to the another... I'll keep the conversion explicit, otherwise it can easily get really confusing . The motto for Scala's advanced features is: "with great power comes great responsibility" :)Directed
I think that the proper name for the function you ask for is called an "Iverson bracket" (google it). So, it must be implicit def ib (b:Boolean) = if (b) 1 else 0 although I prefer the muxes: def mux[T](cond: Boolean, yes: => T, no: => T) = if (cond) yes else no (Scala generously enabled them via by deferred => arguments) enabling mux(cond, 1,-1) instead of bulky if (cond) 1 else -1.Mildamilde
S
67

If you want to mix Boolean and Int operation use an implicit as above but without creating a class:

implicit def bool2int(b:Boolean) = if (b) 1 else 0

scala> false:Int
res4: Int = 0

scala> true:Int
res5: Int = 1

scala> val b=true
b: Boolean = true


scala> 2*b+1
res2: Int = 3
Silken answered 14/4, 2010 at 7:15 Comment(6)
what are the advantages of using implicit without a class?Kliber
@Russ Bradberry, If you try the answer from @Jackson Davis you have to call explicitely the function asInt to do the conversion so doing ==> val a:Int=true is not possible, and so doing ==> (1-true). The conversion is not transparent.Silken
so does this make it global? or do i need to do something special to make this global? also, will this work as something like if I insert into mysql "insert into blah (boolVal) values (" + b + ")", will it automatically assume its the int version and not the bool version?Kliber
@Russ Bradberry. No in your case you concatanate a String with a Boolean so there is no way that the compiler figure out that you want an Int instead of the Boolean. You can cast the value to an Int : "insert into blah (boolVal) values (" + (b:Int) + ")"Silken
@Russ Bradberry it is not global, you can put your implicits into an object and then import them whenever you need todo some conversionSilken
also add import scala.language.implicitConversions - docs.scala-lang.org/tutorials/tour/implicit-conversions.htmlSeedtime
G
17

You can do this easily with implicit conversions:

class asInt(b: Boolean) {
  def toInt = if(b) 1 else 0
}

implicit def convertBooleanToInt(b: Boolean) = new asInt(b)

Then, you will get something like

scala> false toInt
res1: Int = 0
Geraldine answered 13/4, 2010 at 23:48 Comment(1)
This great technique is called "pimp my library".Aegeus
I
16

While using an implicit is probably the best way to go, if you want a quick-and-dirty conversion from boolean to int you can use boolean.compare(false)

Inefficient answered 27/9, 2013 at 11:43 Comment(1)
Caveat: as commented by @KristjanVeskimäe, compare does not guarantee 1, only a positive number - cf. docs.oracle.com/javase/7/docs/api/java/lang/…Acantho
G
7

Actually, I'd expect it to be if (x) 1 else 0, not if (x) 0 else 1.

That's why you should write your own conversions. Integer isn't a boolean, and if you want for some reason to store booleans as integers, then you should hone your own standards of how the truth and not truth are represented.

Boolean "true" is not a number, it is an instance of the Boolean type. Like java.lang.Boolean.TRUE. It can be stored internally as an integer, but that is an implementation detail that shouldn't be leaked into the language.

I'd say that if (x) 0 else 1 is the preferred method of conversion. It is simple and fast.

You can also write x match {case true => 0; case false => 1} if you want to use a more general pattern matching approach.

Geezer answered 14/4, 2010 at 14:34 Comment(1)
well the idea was to convert it to the c standard 0=false, 1=true. But why would i use match rather than the ternary if else?Kliber
A
7

Since Scala 2.10 the solution by Jackson Davis is more often written using an implicit value class:

implicit class BoolToInt(val b:Boolean) extends AnyVal {
  def toInt: Int = if (b) 1 else 0
  def * (x:Int): Int = if (b) x else 0
}

For added comfort I have also added a multiplication operator, as this is the most common use of a Boolean to Int conversion for me. I prefer this over making the conversion itself implicit (solution provided by Patrick), as that loses more of the type control than I want.

Acantho answered 25/9, 2014 at 12:53 Comment(0)
E
6

If you don't want to go the implicit way, this may be useful:

var myBool:Boolean = true
myBool: Boolean = true

myBool.compare(false)
res3: Int = 1

myBool = false
myBool: Boolean = false

myBool.compare(false)
res3: Int = 0
Explication answered 30/8, 2016 at 17:17 Comment(2)
I thought the same first, but the contract of compare only promises a positive number for true.compare(false) . So it may be that a JVM implementation returns sth bigger than 1.Beg
How is this different from answer by Paul Murray?Acantho
P
0

Building on Paul and Gaurav's answers, the closest to a built-in might be b.compare(false).sign. This guarantees that you're getting 0 or 1 and arguably conveys the Iverson bracket intent.

In general, I agree with some of the comments that it's preferable to avoid branching constructs in favor of straight-line method invocations. That's why the API provides methods like getOrElse.

Probably answered 19/2, 2023 at 19:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.