Right, I forgot the third case (iteration), I have edited my previous post.
While in principle I agree, I think your dictum may be a bit strong, given that Scala as a hybrid language explicitly supports a range of programming styles.
Without checking, Iâd guess that the common super type of all these probably is Iterable
, which you suggested to use above. (And note that Iterator
is an abstract trait, as well, not a concrete type.)
However, closer to the OPâs problem, the ânaturalâ abstraction for List
and Vector
would be Seq
- an ordered collection. And this usually works just fine, as long as you donât care about performance specifics, as is often the case for small collections (where big-O characteristics of a concrete collection type can be quite misleading, anyway). Actually, having concrete types specified everywhere might even be detrimental for performance if you are operating multiple libraries that happened to decide on different concrete collection types, forcing you to convert to and froâŚ
As an additional difficulty, the OP added Array
to the mix, which is either a dirty
artifact of the JVM heritage, or a deliberate choice for performance reasons. It is not part of the Scala collection hierarchy proper for obvious reasons. One should either try to get rid of it ASAP (and probably pay a conversion fee) or stick with it and accept the pain points.
So Iâd argue that Seq
is not that bad an abstraction when used cautiously. The alternative you outline as of now requires to buy into a full-fledged eco system on top of Scala, be it scalaz, Cats,⌠You cannot âjust ask for monadâ in plain Scala to start with. While I fully agree with you that going âall inâ on functional style and avoiding subtyping in the large is worthwhile and probably superior in the long run, one has to concur that itâs still a journey down the rabbit hole and that more OO-ish approaches can still be a perfectly valid choice in the Scala world.
Actually I do not consider myself a functional herald, I have always defended Scala for being a mix and I like to use OOP abstractions where it makes sense.
However, I do think that abstracting collections with subtyping doesnât make sense. (Note, this is different to the fact that the stdlib uses a lot of inheritance, I understand that is done to increase reuse of internal code, I just think those traits are just for internal use and mostly useless for users)
Without checking, Iâd guess that the common super type of all these probably is
Iterable
, which you suggested to use above. (And note thatIterator
is an abstract trait, as well, not a concrete type.)
I suggested to use IterableOnce because it allows you to get an Iterator, nothing else.
Also, I do not care if Iterator is a trait
or a class
it is a concrete type in the sense that it has a well defined API with a well defined complexity⌠(this not different at List being a concrete type, despite being a sealed abstract class
, or Option being a concrete type where Some and None shouldnât)
However, closer to the OPâs problem, the ânaturalâ abstraction for
List
andVector
would beSeq
- an ordered collection. And this usually works just fine.
No it doesnât. Can you get the tail
? Can you pattern match? Can you get the length? Can you access by index? Are you even sure it will terminate? (remember both Stream and LazyList are Seqs)
Actually, having concrete types specified everywhere might even be detrimental for performance if you are operating multiple libraries that happened to decide on different concrete collection types, forcing you to convert to and froâŚ
I actually do not care about the performance being good or bad. I care about being able to reason about it.
If you have to convert that is an explicit and conscious decision.
So Iâd argue that
Seq
is not that bad an abstraction when used cautiously. The alternative you outline as of now requires to buy into a full-fledged eco system on top of Scala, be it scalaz, Cats,⌠You cannot âjust ask for monadâ in plain Scala to start wit
Yeah, I agree, and that is really a pain point.
My opinion is that cats is a utility library that most people will use, no matter if they go full pure FP or not. But that doesnât demerit the fact that you need a library to do this, which is kind of sad.
I didnât want to insinuate that - you probably wouldnât have recommended using iterators, if you were.
My âall inâ was rather hinting at my experience that, while vanilla Scala allows rather gradual progress through the paradigm/style space, scalaz/Cats have black hole characteristics - once you pull them in, they start taking over the whole project. Iâm not saying thatâs a bad thing, and maybe Iâve just been holding it wrong.
This still strikes me as an very strong statement. I certainly do have issues with aspects of the Scala collection API myself, Seq
being at the center of quite some of those, but Iâd still place it pretty much on the usable side - Iâve seen worse. Even if I accepted this statement for the standard API, I probably wouldnât want to generalize this - I still donât see whatâd be wrong with a trait for finite, strict, ordered collections that basically only hides the performance differences between the concrete implementations.
The difference between Iterator
and Seq
in terms of complexity doesnât look that striking to me. Both are traits with 2-3 base methods, lots of derived methods, among them some that allow to shoot your own foot.
Apart from length, I think I can - although not necessarily using the âobviousâ methods on Seq
for this purpose. As for length, again, I donât see the difference to Iterator
. But yes, I get and share your point.
Itâs explicit and conscious, but not necessarily a decision. If I need to interop with these APIs, I need to pass my data with the type they require.
That seems to be the other point where we have different experiences. I certainly like Cats, but Iâd think it comes with quite a learning curve (not just the individual concepts, but combining them in a full application), and it feels pretty much all-or-nothing to me. Thus Iâd be hesitant to recommend it as a near compulsory alternative to the vanilla Scala API for everyone.
Start, maybe, although it can take a fair while. Thereâs a bunch of âfree candyâ, in the form of monad transformers and such, that donât necessarily take over.
That said, as soon as you touch IO
, you do wind up sliding down the rabbit hole really fast. (In the process of making that switch at work right nowâŚ)
I didnât want to insinuate that.
Right, I also didnât want to insinuate you insinuate that
It was mostly to put like a context.
Once you pull them in, they start taking over the whole project.
That seems to be the other point where we have different experiences. I certainly like Cats, but Iâd think it comes with quite a learning curve.
Agree to disagree.
I believe you can use many things from cats even if you believe IO
is the worst thing ever (just to make clear this phrase comes for a person I know which still uses cats).
I do believe that cats-effect is a black hole, you go there is you want / like / need pure functional programming.
This still strikes me as a very strong statement.
Yeah, I have to agree it is. That is why I made clear from my first ost it is my opinion, and only that. I am not trying to sold it as the universal truth.
but not necessarily a decision.
Do we really have decision in life or not?
Leaving bad philosophical jokes aside, yes it is a trade-off.
I just believe it is better to transform if needed instead of just hoping the library wonât work with the Seq I provided. (but again, my opinion, based on my narrow scope)
Anyways, I believe we distracted the conversation a bit off-topic.
Mostly my fault, so sorry about that.
And I believe the best would be to leave it here.