Inconsistency of operators

On Fri, Dec 2, 2011 at 11:08 AM, martin odersky wrote:
>
>
> Cay, thanks for the thoughtful suggestions!
>
> On Fri, Dec 2, 2011 at 7:55 PM, Cay Horstmann wrote:
>>

>> And yes, the operators have gotten a bit out of hand in the collections library. I put them all into a table, and the result wasn't pretty. (The problem isn't the operators, but their inconsistency.) There is a lot to like about the collections library, but it's not perfect. Perhaps it needs to get redone one more time, or perhaps Scaladoc needs to be smarter about giving a more user-centric view.
>>
> Do you have suggestions regarding inconsistency of operators? Given a long enough deprecation cycle we could do changes if they are necessary. One other thing I thought of was merging the Traversable and Iterable layers if collections, because this would get rid of about 20% of the supertraits of standard collection classes.

My gripe is with the operators to add and remove items. They are 17
operators + ++ :+ +: ++: :: ::: (for lists) | (for sets) += ++= +=:
++=: (for buffers) - -- &~ (for sets) -= --=

1) Why have ::? You can use +:, of course, but not always--in
particular, not in pattern matching.
2) Why the set operators? Just use ++, --
3) Is it really worth worrying about the difference between + and :+?
I understand that + is supposed to be used for unordered collections,
and :+ for ordered collections. But then shouldn't we also use ++ for
unordered and :++ for ordered? And shouldn't we use :+= instead of +=
for buffers? I think it would be simpler to say "+ and ++ add, and the
addition is at the end for ordered collections".
4) The +: and = don't work well together. += means "add/mutate". :+=
means "prepend/mutate". +:= should mean "append/mutate", but we need
the colon to the right, so it must be +=:. Or =+:? The choice seems
arbitrary. With :: for prepend, there is only one natural choice, =::

I realize it would be painful to eliminate :: for lists. So, I'd give
up on :+, and I'd give up on the distinction between + and +:. What's
left is

+ ++ :: ::: - -- += ++= =:: =::: -= --=

That's 12 operators, one for each choice of
- add/prepend/remove
- one or many
- mutate or not

But if you love + vs :+ vs. +:, then the following 16 operators are a
consistent set:

+ ++ :+ :++ +: ++: - -- += ++= :+= :++= +=: ++=: -= --=

Cheers,

Cay

Re: Inconsistency of operators

My gripe is with the operators to add and remove items. They are 17
operators + ++ :+ +: ++: :: ::: (for lists) | (for sets) += ++= +=:
++=: (for buffers) - -- &~ (for sets) -= --=

These are painful and do not contribute to readable code. I would suggest the following conventions.
+, -  -- obvious++, --  --takes a bit of learning, but obvious once one realizes they generalize + and - so that the rhs is a collection, not a single element.+=, -=, ++-, --=  --obvious generalizations of previous four operators.
...and anything else should be a named method ('cause it's not even _close_ to obvious).
Ken 

Re: Re: Inconsistency of operators

On Sat, Dec 3, 2011 at 12:46 PM, Kenneth McDonald wrote:
>> My gripe is with the operators to add and remove items. They are 17
>> operators + ++ :+ +: ++: :: ::: (for lists) | (for sets) += ++= +=:
>> ++=: (for buffers) - -- &~ (for sets) -= --=
>
> These are painful and do not contribute to readable code. I would suggest
> the following conventions.
> +, -  -- obvious

Funny you say that, because the current use of + for adding a single
element is actually incorrect according to the obvious implementation.
The reasoning goes as thus

The most universally known definition of '+' is from mathematics.
It's used for "adding" real numbers together - although it is first
introduced as adding natural numbers together. This is practically
the first thing we all learn in elementary school.

In elementary computer programming classes we all learn that computers
are actually pretty bad at math. Specifically, they can't really
represent real numbers accurately. So we break the '+' function up to
work with different types, namely: Short => Short => Short, Int => Int
=> Int, Long => Long => Long, Float => Float => Float, Double =>
Double => Double.

We also tend to deal with String concatenation quite a bit, so we also
define the '+' function for strings, String => String => String.

At this point we see a pretty obvious pattern emerging for how we can
generalize this function '+' :: A => A => A.

So, logically if we were to define '+' for Lists and Sets we should
have the types being List[Z] => List[Z] => List[Z] and Set[Z] =>
Set[Z] => Set[Z]. The implementations are obvious - concatenation and
union - and the Z type can be any type because it plays no role in the
implementation.

We can even define '+' for Maps. It's simply a merging of two maps,
with the requirement that the value type also have '+' defined.

At some point in time someone with a better knowledge of math will
come along and say, "Hey, I recognize that! It's called a
Semigroup[1] and if you have a Semigroup and a zero value, you have a
Monoid[2]."

It would be wonderful if we could get these and other really really
useful, simple concepts in the standard Scala library.

[1] http://en.wikipedia.org/wiki/Semigroup
[2] http://en.wikipedia.org/wiki/Monoid

> ++, --  --takes a bit of learning, but obvious once one realizes they
> generalize + and - so that the rhs is a collection, not a single element.
> +=, -=, ++-, --=  --obvious generalizations of previous four operators.
> ...and anything else should be a named method ('cause it's not even _close_
> to obvious).
> Ken
>

Re: Re: Inconsistency of operators

Le 03/12/2011 20:46, Kenneth McDonald a écrit :
{...}
>
> +, - -- obvious
> ++, -- --takes a bit of learning, but obvious once one realizes they
> generalize + and - so that the rhs is a collection, not a single element.
> +=, -=, ++-, --= --obvious generalizations of previous four operators.
>
> ...and anything else should be a named method ('cause it's not even
> _close_ to obvious).

Depend of your background. "::" (cons) is obvious for lots of people,
and for my personal use case, pattern matching on lists with anything
else but "::" would seem alien.

And as said by Paul, on the JVM, "+" is a string concatenation, even at
unexpected times.

Thanks,

Re: Inconsistency of operators

> I realize it would be painful to eliminate :: for lists. So, I'd give
> up on :+, and I'd give up on the distinction between + and +:. What's
> left is
>
> + ++ :: ::: - -- += ++= =:: =::: -= --=
>
> That's 12 operators, one for each choice of
> - add/prepend/remove
> - one or many
> - mutate or not
>

That is a nice concise set

Re: Inconsistency of operators

Yes, sorry, intended to mention :: as a special case.
Ken

Re: Inconsistency of operators

On Sat, Dec 3, 2011 at 7:59 AM, Cay Horstmann wrote:
> 3) Is it really worth worrying about the difference between + and :+?

// This was List("a", "b") in 2.7, when List still had a + operator.
scala> List("a") + "b"
res0: java.lang.String = List(a)b

scala> List("a") :+ "b"
res1: List[java.lang.String] = List(a, b)

scala> Set("a") + "b"
res2: scala.collection.immutable.Set[java.lang.String] = Set(a, b)

scala> Set(1) + "b"
res3: java.lang.String = Set(1)b

There is more you can probably google up; + should be a last resort as
long as any2stringadd is with us.

See also https://issues.scala-lang.org/browse/SI-4059

Re: Inconsistency of operators

Oh great, another inconsistency.

List("a") + "b" // + is concatenation
Set("a") + "b" // + is insertion

You convinced me that it was a mistake to overload + for insertion
into a collection.

So, a better way would be to use ++ for adding one element, +++ for
adding in bulk. It's actually nicely consistent with :: and :::

That gives a list of the following twelve:

++ +++ :: ::: -- --- ++= +++= =:: =::: --= ---=

No, I do not know a way from where we are to this Utopian ideal.

On Sat, Dec 3, 2011 at 11:37 AM, Paul Phillips wrote:
> On Sat, Dec 3, 2011 at 7:59 AM, Cay Horstmann wrote:
>> 3) Is it really worth worrying about the difference between + and :+?
>
> // This was List("a", "b") in 2.7, when List still had a + operator.
> scala> List("a") + "b"
> res0: java.lang.String = List(a)b
>
> scala> List("a") :+ "b"
> res1: List[java.lang.String] = List(a, b)
>
> scala> Set("a") + "b"
> res2: scala.collection.immutable.Set[java.lang.String] = Set(a, b)
>
> scala> Set(1) + "b"
> res3: java.lang.String = Set(1)b
>
> There is more you can probably google up; + should be a last resort as
> long as any2stringadd is with us.
>
> See also https://issues.scala-lang.org/browse/SI-4059

Re: Inconsistency of operators

On Sun, Dec 4, 2011 at 9:12 AM, Cay Horstmann <cay [dot] horstmann [at] gmail [dot] com> wrote:
Oh great, another inconsistency.

List("a") + "b" // + is concatenation
Set("a") + "b" // + is insertion

You convinced me that it was a mistake to overload + for insertion
into a collection.

So, a better way would be to use ++ for adding one element, +++ for
adding in bulk. It's actually nicely consistent with :: and :::

Why not :+ and :++? Then for symmetry you can have +: and ++: to prepend. Oh wait, that's looking almost kinda familiar ;)
--
Derek Williams

Re: Inconsistency of operators

Might be redundant and confusing.

On 4 dec, 17:12, Cay Horstmann wrote:
> Oh great, another inconsistency.
>
> List("a") + "b" // + is concatenation
> Set("a") + "b" // + is insertion
>
> You convinced me that it was a mistake to overload + for insertion
> into a collection.
>
> So, a better way would be to use ++ for adding one element, +++ for
> adding in bulk. It's actually nicely consistent with :: and :::
>
> That gives a list of the following twelve:
>
> ++ +++ :: ::: -- --- ++= +++= =:: =::: --= ---=
>
> No, I do not know a way from where we are to this Utopian ideal.
>
>
>
> On Sat, Dec 3, 2011 at 11:37 AM, Paul Phillips wrote:
> > On Sat, Dec 3, 2011 at 7:59 AM, Cay Horstmann wrote:
> >> 3) Is it really worth worrying about the difference between + and :+?
>
> > // This was List("a", "b") in 2.7, when List still had a + operator.
> > scala> List("a") + "b"
> > res0: java.lang.String = List(a)b
>
> > scala> List("a") :+ "b"
> > res1: List[java.lang.String] = List(a, b)
>
> > scala> Set("a") + "b"
> > res2: scala.collection.immutable.Set[java.lang.String] = Set(a, b)
>
> > scala> Set(1) + "b"
> > res3: java.lang.String = Set(1)b
>
> > There is more you can probably google up; + should be a last resort as
> > long as any2stringadd is with us.
>
> > See alsohttps://issues.scala-lang.org/browse/SI-4059- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -

Re: Re: Inconsistency of operators

Huh?  They're wrappers for Stream.cons.
  --Rex

On Sun, Dec 4, 2011 at 11:48 AM, Dave <dave [dot] mahabiersing [at] hotmail [dot] com> wrote:
#:: and #::: for streams are only wrappers for :: and :::
Might be redundant and confusing.

Copyright © 2013 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland