Return to Level1Techs.com

Flags and bitwise operations in Kotlin

help
#1

Can anyone help me out with the preferred (i.e the Kotlin way) to implement flags in Kotlin?

I have a couple of utility classes for converting Speed and Distance values to different units and formatting the results as strings. So far I’ve only needed to specify whether the resulting string contains the unit suffix or not (e.g “25 MPH” or just “25” etc) so my format function just takes a boolean “withSuffix” paramater which I have defaulted to ‘true’

I now find that I want to expand on the formatting options, so I would like to replace the “withSuffix” paramater with “formatOptions” value. In Java, C/C++ I’d use an integer bitmap of options:

enum FormatOptions {
    WITH_SUFFIX                 = 1 << 0,
    WITH_DECIMAL                = 1 << 1
    // Etc...
}

And just bitwise OR the flags together.

I know Kotlin has the “Or” and “Shl” I need but I can’t find any examples of people actually using them for this purpose.

When I’ve searched I’ve found some suggestions that EnumSet (from the Java runtime) is the way to go.

I’d like to default the formatOptions parameter to an empty set, so, I am trying to do something like this using the EnumSet.noneOf() function:

enum class FormatOptions {
    WITH_SUFFIX,
    WITH_DECIMAL
}

fun formatSpeed(speed: Float, sourceUnit: SpeedUnit, format: Format, formatOptions: EnumSet<FormatOptions> = EnumSet.noneOf(FormatOptions.class)): String {
}

But for some reason the Kotlin compiler is not recognising the “class” property of the FormatOptions enum. Unfortunately all the examples I can find are in Java and the method of instanciating an empty EnumSet is shown as:

EnumSet<MyEnum> theSet = EnumSet.noneOf(MyEnum.class)

So in Kotlin it should be something like

val theSet: EnumSet<MyEnum> = EnumSet.noneOf(MyEnum.class)

or

val theSet = EnumSet.noneOf(MyEnum.class)

But I can get this to work in Kotlin, the compiler complains that “class” is unknown

Am I missing something and is there a better way to do this? (I thought about creating an Options class and passing something like Options.apply { withSuffix = true, withDecimal = false } but I am not too keen on that)

Cheers

0 Likes

#2

Doh … nevermind … as usual after I clicked POST I found the solution (to the syntax error anyway).

I forgot that Kotlin has a different method for accessing the “class” of an object so that you can differentiate between the Java and Kotlin classes.

The code should be :

val theSet: EnumSet<MyEnum> = EnumSet.noneOf(MyEnum::class.java)

So this is the way to do it with EnumSet():

enum class FormatOptions {
    WITH_SUFFIX,
    WITH_DECIMAL
}

fun formatSpeed(speed: Float, sourceUnit: SpeedUnit, format: Format, formatOptions: EnumSet<FormatOptions> = EnumSet.noneOf(FormatOptions::class.java)): String {
}

That part is solved but if anyone still has some suggestions on better ways to pass flags to a function in Kotling I’d be interested.

0 Likes

#3

You could do the formatting in the enum. Say if you wanted a enum class that adds m or mm to a number.

enum class WeightFormat(val unit : String) {
   METER("m"), CENTIMETER("cm");

   fun format(num : Double) : String = "$num $unit"
}

Or if formats are very different

enum class WeightFormat(val unit : String) {
   METER("m") {
      fun format(num : Double) : String = "$num $unit"
   }, 
   CENTIMETER("cm") {
      fun format(num : Double : String = "$unit $num"
   }
}

But its really down more to preference than anything else.

EnumSet I`m not sure why you’d use that. I’d either make it nullable and set it to null per default or a List or vararg. vararg is similar to ... in java. You can add as many of one thing as you want and you can use it as an array. vararg does not work if it’s not the last parameter. So then you gotta use a List or Array. EnumSet I’m not really sure what the purpose is other than using another more different List.

fun formatAll(num: Double, vararg formats: WeightFormat): List<String> {
    val result = mutableListOf<String>()
    formats.forEach { cur -> result.add(cur.format(num)) }
    return result
}

fun formatOne(num :Double, formatter : WeightFormat? = null) : String {
    return if(formatter != null)
        formatter.format(num) 
    else num.toString()
}

I’m also curious how you intend to bitwise and together the flags, since what I understand of bitwise and is this

12 = 00001100 (In Binary)
25 = 00011001 (In Binary)

Bit Operation of 12 and 25
   00001100 and
   00011001
   ________
   00001000  = 8 (In decimal)
0 Likes

#4

Unfortunately this would have the same restrictions as my previous version of the code. Before I just needed to be able to tell the formatting function if I wanted the formatted string to contain the unit suffix or not so I just passed in a boolean flag and defaulted it to true (In most cases I wanted the suffix in the string). Now I need to be able to specify if the speed should be a whole number or a decimal so I have more than one option and will probably be adding some more.

Rather than add another boolean, I figured I’d just use a bitmap in the same way I would do it in Java or C++, so something like

val formattedSpeed = FormatUtils.Speed.toString(speed, FormatOption.WITH_SUFFIX|FormatOption.WITH_DECIMAL)
or
val formattedSpeed = FormatUtils.Speed.toString(speed, FormatOption.WITH_SUFFIX)
or
val formattedSpeed = FormatUtils.Speed.toString(speed)  // Using defaults

I know I could do this with Kotlins bitwise “Or” (and “And” to check the flags)

I think I’d end up in a similar situation if the code were in the enum class, I’d still need a way to pass more than one option.

It was when I did a search for the Kotlin way to handle bitmap and flags that I found the EnumSet(). I found it mentioned on Stack Overflow in a few posts. The Android development documents mentions that it is supposed to be a more clear and type safe way to do bitmaps in Java. It’s implemented internally as a BitSet so is space efficient and supposed to be optimised enough to be a valid replacement for bitmaps/flags.

Setting the options to null could work but I am trying to avoid introducing a nullable since avoiding null unless absolutely necessary is one of the main concepts behind Kotlin.

At the moment I’ve gone with the EnumSet and have code like this:

val formattedSpeed = FormatUtils.Speed.toString(it, speed, SpeedUnit.MPS, Preferences.getSpeedFormat(it), EnumSet.of(FormatUtils.Speed.FormatOption.WITH_SUFFIX))

EnumSet.of(FormatUtils.Speed.FormatOption.WITH_SUFFIX) part of the call is the replacement for bitwise ORing the flags but it allows me to do checks like this inside the formatting function

val formatString = if(formatOptions.contains(FormatOptions.WITH_DECIMAL) "%.2f" else "%d"

and

if(formatOptions.contains(FormatOptions.WITH_SUFFIX)
    str.append(suffix)

Because I default formatOptions to an empty EnumSet() I don’t need to check for nulls everywhere.

Anyway, thanks for the suggestions. I’ll have another think about it. There’s just something telling me that there has to be a neater way to do this in Kotlin that I just haven’t come across yet.

0 Likes

#5

The way I would do it in Java and C++ would be to OR the flags together when calling the method and then inside the method I check the bits in the bitmap using AND

So it would be something like this (in pseudo Java)

enum FormatOptions {
    WITH_SUFFIX = 1 << 0,
    WITH_DECIMAL = 1 <<1
}

String formatSpeed(float speed, FormatOptions options) {
    String formatStr = (options & WITH_DECIMAL) == 0 ? "%d" : "%.02f"
    String str = String.Format(formatStr, speed)

    if((options & WITH_SUFFIX) != 0)
        str.append(suffix)

    return str
} 

And call the function like

String formattedSpeed = formatSpeed(speed, FormatOptions.WITH_SUFFIX|FormatOptions.WITH_DECIMAL)

I could do this in Kotlin with “Or” and “And” but from what I can see, no one seems to suggest this and I can’t seem to find any Kotlin code that does, which is why I am wondering of there is a specific, better, way to do this in Kotlin

0 Likes

#6

Interesting. I’ve never thought of using bit operations for flag type of things. Kinda complicated for something so simple.
It’s the kind of code I would have to pull out a piece of paper and start writing down bits to understand sooner or later. :smile:

But maybe that would be clearer if I was actually using bits in code a lot.

I would in this case just have a List of formatters that take strings and return strings and apply them all in a loop.

Set’s don’t allow duplicates so that may be the only desireable part of EnumSet.

0 Likes

#7

Ah, I am coming form a background in C and Assembler so I’ve spent a lot of time doing bitwise operations so when I need to pass a set of flags around it’s the first thing I think of.

With Java I could do it the same way as in C (which is probably why I’ve only just discovered EnumSet()) but now with Kotlin I am trying to embrace the language features so second guessing everything and looking for neat ways to do things using all the new fancy Kotlin construts.

As far as I know it’s a specialised set and is implemented as a BitSet<> so internally it only stores a set of 1 & 0’s and does all the bitwise operations for you so it’s quite fast too.

0 Likes

#8

Yeah that clearly seems to be that way. ^^

Sure the if is fast, but you don’t need to do an if. If all you want to do is apply all the formatters you got. It’s easier to read and maintain imo to loop threw them. Since if you don’t put the formatting logic into the formatter, you will have to do as many ifs as you got formatting options to select the right formatting logic vs potentially not a single if unless you want some combination of formatters to throw an exception or something.

0 Likes

#9

I am not sure I follow, are you suggesting that I pass the formatting logic in to the function? Either via the FormatOptions Enum or some other callable object?

I do something similar to convert between different speed units (MPS, MPH & KPH) via a SpeedUnit enum modelled on the Java TimeUnit enum. This works very well for the conversion, but I am not sure it would be an option for the formatting unless I am missing something.

In simplified form it’s something like:

enum class SpeedUnit {
    MPS {
        fun toMPS(s) = s
        fun toMPH(s) = s * 2.236936f
       fun toKPH(s) = s * 3.6f
    },

    MPH {
        // Conversion functions here...
    },

    KPH {
        // Conversion functions here...
    }


    abstract fun toMPS(s): Float
    abstract fun toMPH(s): Float
    abstract fun toKPH(s): Float
}

I pass the sourceUnits into the formatter then just call sourceUnits.to???() depending on what the target units are

I am trying to think of how I could do something similar with the formatting, wouldn’t I need to have a formatting function for each options combination?

enum class FormatOptions {
    NONE {
        fun toString(s: Float) = String.format("%d", s.toLong())
    },

    WITH_DECIMAL {
        fun toString(s: Float) = String.format("%.2f", s)
    }.

    WITH_SUFFIX {
       // Hmm, now I need to know the speed unit to choose the right suffix?
    },

    WITH_SUFFIX_AND_DECIMAL {
        // Hmm, now I need to call WITH_DECIMAL and WITH_SUFFIX
   }


    abstract fun toString(s: Float): String
}

I am not sure if this is what you mean, but I can see it getting very complex if I need to add more formatting options, because I’d like to be able to have any combination of options

You mentioned looping over formatters, do you mean passing in an array of formatting callables and building up the formatted string by iterating over the array of formatters? If that’s correct, would the order of operations be the order they are specified in the array? E.g would it then be down to the caller to make sure that the “suffix” formatter was applied last and if I decide in the future that I need a prefix the calling code would need to ensure that the prefix formatter gets executed before the rest?

The idea certainly has me thinking though … :smiley:

0 Likes

#10

I mean basically, yeah. You can always validate your input in the formatting options and then throw exceptions if the input is not valid to be formatted with it. I think that is ok since formatting is kinda an UI/UX thing. If you allow selecting formatters together that can never succeed that is not really the formatters problem.

I’ve never needed to apply many different formatters at once. At most I had worked on projects where we had one formatter per language, per type of thing we want to format.

Chances are you know more about your project than I do. So, you should evaluate what you think is more suited for it.

1 Like

#11

Thanks for your suggestions. I am probably over thinking things to much because I am focusing on “the Kotlin” approach but will probably just end up doing something simple. It’s not any important project just an android application I am writing to get up to speed on Kotlin.

For context, here’s where the formatted values are displayed

I am using the Speed formatting utility functions for all the values in the speed panel but I have decided that the current speed (the large font) doesn’t need to show a decimal value (it was already using the withSuffx = false option) … which led me to changing the function to accept more fine grained formatting flags.

Anyway, thanks again for your help and suggestions, I have a few different ideas now on different ways I can approach this.

Cheers,

Shecks

0 Likes