Vavr: Rename collections because of name clashes with java

Created on 19 Aug 2017  路  24Comments  路  Source: vavr-io/vavr

Draft (discussion also here):

img_9500

I also think

  • Seq could be Sequence or Sequential
  • CharSeq should be StringSeq
  • Mapped (aka Map) could be Indexed
  • The extended collections Multiset and Multimap could stay as-is or be renamed to MultiDistinct and MultiIndexed resp. MultiMapped.

A Map is an indexed collection, i.e. its elements are values, not (key, value) entries. See also #1634 and this Twitter conversation.

img_9502

!BACK-COMPAT desigrefactorinimprovement revertecloseduplicate 芦vavr-collection禄

Most helpful comment

My preferred solution is to not rename the collections.

All 24 comments

The most simple and straight forward solution seems to me our current strategy:

Designing persistent collections as they should have been from the beginning, especially taking the most common and concise names as possible.

Not implementing Java's old-school interfaces means reducing the overall complexity and keeping control over the library.

See the discussion on our blog.

My preferred solution is to not rename the collections.

As someone who is using vavr across multiple code bases, it would be disappointing to see the collections renamed. When we went all in on vavr, conflicts tended to be a non-issue as we rarely needed to import java.util.* anyway. And if I did need both, I can live with fully qualifying java.util.List occasionally.

I think the argument for retaining recognizable type names is very strong as well. In a team setting, getting developers to buy into a new collections library is hard enough, and if someone unfamiliar couldn't recognize any of the types, that would be a hard sell. I think moving away from familiarity for a library like this would greatly hurt adoption.

Adding a collections library definitely has some interesting choices, I think the path you are already on is a solid one. We love the safety and elegance vavr brings to Java. Thanks for the awesome library!

I am using it with javaslang.xx.List銆倀hen all people know it's a List.

@zlangbert thank you, great to hear that you like Vavr :)
It is important for us to receive this kind of feedback from bigger companies.

As I am working on growing the vavr user base in our company the most salient (and valid IMO) concern is that users may make mistakes when they think they are using a java.util.List but in fact are using a io.vavr.List. This is especially important for developers not familiar with anything but imperative.
I am following the fqdn-for-JUL-collections recommendation and that seems to take the edge off concerns but not enough to douse the flames entirely.
Changing to io.vavr.vList vs java.util.List or similar would be fine with me. Not sure if that will silence critics entirely though.

Hope this helps even though not conclusive in any way :-)

Thanks @andreasaronsson!

Daniel,
Thank you for an awesome library. I have been using it to learn functional Java without the theory barrier presented by Scala - Thank you.
I do not have a huge code base on Vavr but I believe avoiding the name conflict will be better in the long run. Why not take a leaf from the pCollection guys, and simply prepend a v (vavr) to the collections library?
List -> VList e.t.c as proposed by @andreasaronsson?

just want to mention that I love the brevity of Seq, Set, List, Map. It makes the code more elegant to return Seq instead of Collection as opposed to before.

In our codebase (which is a rather small one!) we managed to almost get rid of java.util imports since there is jackson and spring-jpa support for vavr anyway.

I think, if you choose to use vavr it fundamentally changes development - since it is used as a core library or not at all. Furthermore you would want to avoid mixing juCollections and vavrCollections any ay. As it becomes a replacement for juC we don't mind possible name clashes.

One more important thing: It should be considered that some people come to vavr from Scala or are educating themselves about FP via Scala courses (e.g. the Odersky one on coursera). For these people it is VERY helpful that vavr follows the naming conventions of Scala!

@a1730, @alwins0n thank you for your feedback!

I'm starting to use vavr on an existing codebase, and the FQCNs for java/vavr List are not great (though I do generally agree with vavr keeping the List name as is).

FWIW a nice hack that I got used to with jOOQ was using Seq for everything, b/c Seq doesn't overlap with any existing Java collections.

I'd like to do this with vavr as well, but there is no Seq.ofAll or Seq.range, so I end up stuck using a FQCN List merely to get at the factory methods.

Granted, there is API.Seq(...), but only for T and T....

So, if the API could have Seq shortcuts for most of the List factory methods, I think that would go along way towards my "just use Seq" compromise.

Is that doable/reasonable?

Hi @stephenh,

I thought about it but think that's not the right way. It looks like a workaround, we should solve the real issue.

It showed that completely new names are no option, it will introduce new problems. Currently I tend to add the 'P' (= persistent) prefix because it is a common way to name persistent collections (I have seen it in different places) and it will not obfuscate the collection names too much.

I can give our experience of migrating a pretty large codebase from java collections & streams to vavr, and still today mixing both (because of using JPA for DB access, we must still use java's collections for DB entities).

we have no issue with the naming, even though we use vavr List. We would have even less had we decided to use vavr's Vector since java's version is obsolete and non-generic. It is a bit of an annoyance because there must be some switchover point where you go from default import being java.util.List and having to have an explicit io.vavr.collection.List to the final state when you have a default import to vavr and an explicit java.util.List.

I must add, this may seem funny, it helped us no end that vavr picked append() while java has add(). Immediate compilation failure when porting old code, which is great because of the difference in behaviour -- java.util's version is side-effecting and for vavr you must overwrite the variable or else the effect is not taken into account!

@emmanueltouzery you should check my comment for another issue. I think Findbugs or ErrorProne would help us check that we don't ignore a return value from a method that creates a new persistent collection, we just need to make vavr support it.

This video might give a hint as to where the JDK is heading in the future in this regard. Example of 'common way' @danieldietrich mentioned.
https://youtu.be/E1RXMCQ7k9g
Also very interesting! :-)

Initially, I liked all the features that vavr presents. But as soon as I realized that the List is not the java.util.List, it was a big turn off for me. My suggestion is using v prefix for any vavr type that has a name conflict with the standard java correspondence. Like VList or Vlist or vList.

@hrzafer same here. We won't use the collection-part of vavr because of this (or sparingly.)

There is absolutely no reason for which a generic List should be named VList or Vlist or vList.
This denotes poor style, to say the least.
A serious software engineer (unlike some that bother to spam this thread) might think that VList is a List that has some sort of V characteristic.
Unless V is an encoding that is descriptive for a well-understood domain (which is not the case here, as we are talking about a generic collection), why bother?
A type is a type, whose name should be self-descriptive, precise, and denote what it abstracts over, and encoding information about the namespace in which the type resides (for example), in the type name, is bad practice.
This reminds me about the stupid debates (that are still going on, seems like) about the usefullness of hungarian notation in statically typed languges.
The fact that other collection libraries chose to do something like this, is irellevant.
@danieldietrich we appreciate the fact that you took the time to understand our opinion. Seeing you the professional that you are, we believe you are going to make the right decision and ignore all this nonsense. Specifically, you can ignore @hrzafer and @Dangercoder in particular, not only because their proposal is unsound, but also b/c they did not bother to argument their position ("it was a big turn off for me" is not an argument in this situation).

@RazvanPetruescu thank you for giving us insights on you opinion, I really appreciate it. I will take your thoughts into account.

However, I will not ignore @hrzafer, @Dangercoder or any other involved person who spends time on thinking about Vavr.

background: I started using vavr some time ago, mostly on my own projects and a little bit on production.

I don't think that this name clash is any serious issue. I very rarely now have a codebase where java.util.List and vavr List are used together, I simply replace all java.util with vavr counterparts and tell my IntelliJ not to suggest imports for collections from java.util.

Also, I find the static api like List() to be really compelling and so do people I work with.
List() is better than ImmutableVavrList() for me :)

Having said that, I vote to stay with current naming as this IMO is not a problem at all.
The more serious problem is rather that all Java ecosystem uses standard java.util collection and vavr counterparts diverge there and it is kind of cumbersome to insert .toJavaXXX and List(javaish) everywhere. But I don't think that there is sound solution to that at the moment.
disclaimer: Might been doing things wrong, but I'm still exploring vavr. Nonetheless I find it awesome!

There are two opinions:

  • leave it as-is
  • rename it (different suggestions)

The path of least resistance is to leave all as-is (also good for backwards-compatibility).

Makes sense; I'll (...re-) articulate a 3rd opinion: make converting between the two (JVM List and Vavr List) in mixed code easier.

E.g. I invariably end up with java.util.List imported (legacy/mixed code), so it "wins" the List.factoryMethod namespace (and ofAll is too generic to import as a static method), so in every project I use vavr on, I end up with a VavrUtils that is:

  /** Shortcut since API.SeqOfAll does not exist. */
  public static <T> Seq<T> Seq(Iterable<T> list) {
    return io.vavr.collection.List.ofAll(list);
  }

More generically, once java.util.List is imported, I don't know of an easy (specifically succinct) way to convert a java List into a vavr List/Seq to get all the nice methods that I want.

I thought the API.FactoryMethod idiom as a nice way around that, but it seems incomplete, e.g. does have not methods for Iterable<T>.

...in retrospect, this is probably a separate issue (flushing out API factory methods), and basically exactly what I said ~a year ago, so it is probably not that helpful; but I guess the context is "this is a specific pain point (not being able to access the List.ofAll factory methods in mixed code) that made me want 'different names'". Solving that pain point, of easily accessible factory methods, makes the same name issue less annoying (and, FWIW, I totally agree with your resolution of leaving as-is).

@stephenh Thanks for the input. The problem with the API.Seq(...) overloads was that they lead to ambiguities when having Seq(T), Seq(T...) and Seq(Iterable<T>).

I wish there were other ways in Java, like

  • import aliasing: import io.vavr.collection.{ List as VList, Set as VSet }
  • type aliases: type VList = io.vavr.collection.List

Another alternative would be conversion methods

final class API {
    static <T> io.vavr.collection.Seq<T> toVavr(java.util.List<T> javaList) {
        return io.vavr.collection.Vector.ofAll(javaList);
    }
    static <T> io.vavr.collection.Set<T> toVavr(java.util.Set<T> javaSet) {
        return io.vavr.collection.HashSet.ofAll(javaSet);
    }
    static <T> io.vavr.collection.SortedSet<T> toVavr(java.util.SortedSet<T> javaSortedSet) {
        return io.vavr.collection.TreeSet.ofAll(javaSortedSet);
    }
    static <K, V> io.vavr.collection.Map<K, V> toVavr(java.util.Map<K, V> javaMap) {
        return ...;
    }
    static <K, V> io.vavr.collection.SortedMap<K, V> toVavr(java.util.SortedMap<K, V> javaSortedMap) {
        return ...;
    }
}

Usage:

// new API module starting with v1.0
import static io.vavr.api.API.*;

var list = java.util.List.of(1, 2, 3);
var vavrList = toVavr(list);

Naming:

Instead of toVavr(list), we could also name it persist(list) or s.th. else...

Thanks for the response! Yeah, understood on the API.Seq(...) overload ambiguities; would be great to do API.Seq(javaList) if it wasn't for that as then static import of API would solve everything.

API.SeqOfAll(javaList) matches Seq.ofAll / List.ofAll pretty closely but isn't as slick...

I really like API.toVavr, and I think, for me, that would solve this particular "conversion when List is already taken" pain point really well.

Scala's Seq has probably ruined me but I'm even tempted by API.vavr because in the midst of a code block, when I want to do a quick vavr(list).map(...).toList(), the extra few characters between toVavr and vavr "counts", as the whole reason I'm bringing in Vavr in the 1st place is to have the pleasant succinctness of things like .toList() instead of .collect(toList()) and friends. ...granted, that is probably too extreme, but FWIW.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

maystrovyy picture maystrovyy  路  3Comments

nfekete picture nfekete  路  5Comments

carnott-snap picture carnott-snap  路  4Comments

ashrwin picture ashrwin  路  6Comments

paplorinc picture paplorinc  路  6Comments