Idiomatic way to expose a property using a more narrow type

I know, the title sound complicated let me try to give an example,

In java I could have the following class:


class InJava {
  private HashSet<String> flags = new HashSet<String>();
  public Set<String> getFlags() { return flags; }
  private void useFlags(){
    flags.add("some-flag");
  }
}

In the above class I have a single field of type HashSet that exposed as a Set
In kotlin, I will have to do something like:

class InKotlin {
  private val _flags = HashSet<String>()
  val flags: Set<String> get() = _flags

  private fun useFlags() {
    _flags += "some-flag"
  }
}

Whats bothers me is the _flags property - is there a better idiomatic pattern for such cases?

To clarify:
The idea is that I do not want to reveal unnecessary implementation details to my library users - for he/she it should not be visible that I chose to use HashSet internally - but only Set - this is the pattern that I am trying to find an idiomatic way to doā€¦

In the case of the above example, I also do not want the library user to depend on the fact that currently the set is mutable as this can change in later versions of the library. Therefore, I would like to have a field that is of type HashSet but from outside of the class it is seen as if it is just a Set

7 Likes

In Java the example actually only works, because a Java Set is mutable and thus has an add method. If you change Set in Kotlin to a MutableSet you can use a simple val similar to Java.

class InKotlin {
    val flags: MutableSet<String> = HashSet<String>()

    private fun useFlags() {
        flags += "some-flag"
    }
}

If you want to expose an immutable set, I think your solution with a backing property is idiomatic, but Iā€™m new to the language.

@cmayrh,
Thanks but I think you missed my point, even if java had a class: ImmutableSet that HashSet implements the following example will still work because I am directly accessing the field of the class, which I could not do in kotlin.

class InJava {
  private HashSet<String> flags = new HashSet<String>();
  public ImmutableSet<String> getFlags() { return flags; } //assume that HashSet implements ImmutableSet
  private void useFlags(){
    flags.add("some-flag");
  }
}

The idea is that I do not want to reveal unnecessary implementation details to my library users - for he/she it should not be visible that I am chose to use HashSet internally but only Set - this is the pattern that I am trying to find an idiomatic way to doā€¦

In the case of the above example, I also do not want the library user to depend on the fact that currently the set is mutable as this can change in later versions of the library. Therefore, I would like to have a field that is of type HashSet but from outside of the class it is seen as if it is just a Set

2 Likes

I think you can do that like this:

class InKotlin {
	private val _flags = HashSet<String>()
	
	val flags: Set<String> get() = _flags // projection to read-only set
	// or:
	val flags2: Set<String> get() = _flags.toSet() // make a copy of internal set
	
	fun useFlags() {
		_flags += "some-flag"
	}
}

@madmax1028,
Thanks, But as you can see in my question I am trying to avoid the intermediate _flags variable as it just adds clutter to the program that would not exists in the java equivalent

3 Likes

I think it is idiomatic. Similar example here.

You might also do something like this:

interface ReadOnlyView {
    val flags: Set<String>
}

class MutableImpl : ReadOnlyView {
    override val flags = HashSet<String>()

    fun useFlags() {
        flags += "some-flag"
    }
}

Then expose the object as one or the other, as fits each use caseā€¦

2 Likes

@vbezhenar, yes It seems so - too bad, it really seems (to me) like a design flow
I expected something like:

val flags: HashSet<String>  public get: Set<String>

which of course does not workā€¦

@mslenc, Thanks, I actually think that this is a valid option for some cases but for others it just replaces one ceremony with anotherā€¦

4 Likes

Another alternative. Not much different than yours, but only one variable. flags has to be var so the += will work, which then means one must ā€˜protectā€™ the set method.

Not as clean as what youā€™re looking for, but I suspect this wonā€™t change in Kotlin.

You have a mutable object internally, so somewhere, you have to explicitly protect it from modification.

    class InKotlin {
       var flags: Set<String> = HashSet()
       private set(value) = {}
       private fun useFlags() {
           flags += "some-flag"
       }
   }

The bytecode produced is very interesting. Using Intellij decompiler, yours results in the following. Note the useFlags method that constructs a new HashSet everytime.

public final class InKotlin {
  @NotNull
  private Set flags = (Set)(new HashSet());
  @NotNull
  public final Set getFlags() {
     return this.flags;
  }
  private final void setFlags(Set value) {
     flags = value;
  }
  private final void useFlags() {
     this.setFlags(SetsKt.plus(this.flags, "some-flag"));
  }
}

wherease mine produces this. It adds the item, BUT it assigns the string to a variable first. Take your pick.

public final class InKotlin2 {
   private final HashSet _flags = new HashSet();
  @NotNull
  public final Set getFlags() {
     return (Set)this._flags;
  }
  private final void useFlags() {
     Collection var1 = (Collection)this._flags;
     String var2 = "some-flag";
     var1.add(var2);
  }
}

This should also work, though I donā€™t think its idiomatic:

class InKotlin {
    val flags: Set<String> = HashSet()
    private fun useFlags() {
        (flags as MutableSet) += "some-flag"
    }
}

That said, I always go with the private backing field named with an underscore, because that matches what Iā€™ve seen in the Kotlin documentation, so it should surprise other people who read my code the least.

It would be nice to have concise idioms for ā€œpublicly readable, privately writableā€ and ā€œpublicly immutable, privately mutableā€, preferably idioms that can be combined easily. It seems like they are fairly common use-cases.

1 Like

@Mike_Wilkes, thanks but as you said yourself it creates a new set every time which means that it actually quite dangerous paradigm to use as It not only hurt performance but also can make thread-safe classes not thread-safe anymore e.g.,:

class ThreadSafe {
       private val _flags = ConcurrentHashMap.newKeySet<String>()
       val flags:Set<String> get() = _flags
       fun addFlag(flag: String) {
           _flags += flag
       }
}

class NotThreadSafe {
       var flags:Set<String> = ConcurrentHashMap.newKeySet<String>(); private set
       fun addFlag(flag: String) {
           _flags += flag 
       }
}

In the NotThreadSafe class two threads can call the addFlag method on the same time and the result may be that only one of their flags will be added while in the ThreadSafe class this cannot happenā€¦

Please note Kotlin has no notion of fields. There are only properties and property is considered to be an atomic entity, rather than a shortcut for two methods and field. This design allows to express cleanly many use cases without introducing too many concepts.

Property implementation is encapsulated and may be implemented in different ways depending on the runtime target. As such it may or may not have a backing field, but more important is that Kotlin, the language does not have a notion of ā€œfieldsā€. For some targets, it creates automatic properties to expose fields of the host runtime, and can emit fields for specially annotated properties, but these are implementation specifics.

With this in mind, what you are asking boils down to a single property having different types when it is accessed within and outside the object interface. The idiomatic way is to define private property with the desired type and have second public property delegating to it. It is explicit, conceptually simpler, and still more concise than java bean prop.

1 Like

@ddimitrov, Yes, I am aware of this, I only used the term ā€œfieldsā€ in the problem description since I am comparing to the java solution.

But this discussion is not about accessing fields vs. properties but about an idiomatic way to expose minimal implementation details from a class in the form of a property, indeed, as it seems for now - declaring a private ā€œimplementationā€ property and a public ā€œexportingā€ property which delegates to the ā€œimplementationā€ property is the way to go.

I would like to note though, that in my eyes it misses some of the main ideas of properties and goes back to the ideology of a private field and a getters/setters, think about it, you are following the same ceremony :
define a private field => define a private implementation property
define a public getter function => define a public exporting property
Only now you have to do some ugly name mangling on the propertiesā€¦

3 Likes

You may perceive it that way, but I prefer to see it as clearly delineated internal and external interfaces. It is not a pointless ceremony - the internal property has semantics - you may use it to hook delegates, etc.

And it is up to you whether you resort to name mangling or give it a more human sounding name (how about mutableFlags?)

I agree thread safety is an issue. Thank you for raising it as I wasnā€™t considering that.

I think you mis-understood my post, and therefore got your ThreadSafe and NotThreadSafe implementations reversed.

The variation you originally posted is NOT thread safe, as it uses Sets.plus(_flags, newItem) and assigns that using a setFlags method.

My variation uses flags.add(newItem)

Having _flags as a val, and doing += results in a call to Sets.plus(_flags, newItem) whereas defining it as a var, results in usage of add.

@ddimitrov Brings up very valid points. If you want to hide internal implementation, then truly hide it, and use descriptive names.

I suspect weā€™re still thinking too Java here.

@Mike_Wilkes,
+= is not the plus method but the plusAssign method, the following is the method code (copied from kotlin stdlib):

/**
 * Adds the specified [element] to this mutable collection.
 */
@kotlin.internal.InlineOnly
public inline operator fun <T> MutableCollection<in T>.plusAssign(element: T) {
    this.add(element)
}

As can be seen, the method calls the setā€™s add method, since the set itself is threadsafe, so its add method and therefore the implementation is threadsafeā€¦

1 Like

@ddimitrov, I guess we will agree to disagree on this one :slight_smile:

In my eyes, kotlin is a pragmatic language and as such it should have simple idiomatic-promoted ways to do pragmatic day-to-day patterns - the implementation/exposing-properties pattern seems to me like a workaround more than a conscious design choiceā€¦

To be clear - I am not saying that it is not the idiomatic way (as from the documentation it seems it is) I just saying that In my eyes it could have been more elegantā€¦

5 Likes

Hmmm. My apologies. Looking at bytecode again, it would appear I reversed the 2 representations in my post.

Does show the importance of occasionally visiting the Bytecode to see whatā€™s produced, and verify itā€™s ok for your scenario, and to better understand what the compiler is producing.

I agree with @bennyl. I figured that the Kotlin compiler, with all of its advanced type inference, would be able to handle a property with an explicit, immutable type declaration, and an internally typed mutable value, or at least be able to override the getter return type explicitly.

Another alternative in the absence of the way that feels right, is to create a private property of the mutable type then a public getX() function returning the private property as the immutable type.

private val stuff: MutableStuff

fun getStuff(): ImmutableStuff { return stuff }

but then you lose the cleaner property syntax when invoking getStuff().

I searched this issue out because I am developing Android and I want to expose a LiveData property but use MutableLiveData internally to change the value.

1 Like

There is a keep about this issue here:

2 Likes