if(Option)

294 views
Skip to first unread message

Manuel Bernhardt

unread,
Aug 20, 2013, 11:44:56 AM8/20/13
to scala-l...@googlegroups.com
Hello,

I was wondering what people are thinking about this idea:

val foo = Some("thing")
val bar = None

if (foo) {
  // this code will run
}

if (bar) {
  // this code won't run
}

instead of

if (foo != None) / if (foo.isDefined) ...

I.e., a similar notation as how things go in dynamic language such as Javascript.

Does that look like a useful addition to the language (or a macro), or what do you think?


Manuel

Paul Phillips

unread,
Aug 20, 2013, 11:48:31 AM8/20/13
to scala-l...@googlegroups.com
On Tue, Aug 20, 2013 at 8:44 AM, Manuel Bernhardt <bernhard...@gmail.com> wrote:
Does that look like a useful addition to the language (or a macro), or what do you think?

implicit def optionToBoolean(x: Option[_]): Boolean = x.isDefined

I wouldn't want it, but you can give it to yourself.

See also Option#foreach, Option#fold, Option#map, and a bunch of other ways to do that.

Rex Kerr

unread,
Aug 20, 2013, 11:48:38 AM8/20/13
to scala-l...@googlegroups.com
Why do we prefer this than

  foo.foreach{ x =>
    // this code will run
  }
  bar.foreach{ x =>
    // this code will not run
  }

?

  --Rex


--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Antoine Gourlay

unread,
Aug 20, 2013, 11:54:51 AM8/20/13
to scala-l...@googlegroups.com

Being able to use an Option as a Boolean feels a little too much, but maybe something like:

implicit class BoolOption(val o: Option[_]) extends AnyVal {
  def apply(): Boolean = o.isDefined
}
if (!foo()) println("oops, foo is not defined")

Although foreach, or pattern matching, usually seems enough.

Mushtaq Ahmed

unread,
Aug 20, 2013, 11:57:41 AM8/20/13
to scala-l...@googlegroups.com


--

Denys Shabalin

unread,
Aug 20, 2013, 12:05:09 PM8/20/13
to scala-l...@googlegroups.com
You don't macro annotations for funtionality that can be easily implemented in bare scala.

Alec Zorab

unread,
Aug 20, 2013, 12:13:29 PM8/20/13
to scala-l...@googlegroups.com
I think you accidentally the verb?

Oliver Ruebenacker

unread,
Aug 20, 2013, 12:15:42 PM8/20/13
to scala-l...@googlegroups.com

     Hello,

On Tue, Aug 20, 2013 at 11:44 AM, Manuel Bernhardt <bernhard...@gmail.com> wrote:
  If it turns out to be Some, don't you want the value of it, too? Why not:

  myOption match {
    case Some(value) => ???
    case None => ???
  }

     Take care
     Oliver

--
Head of Systems Biology Task Force at PanGenX (http://www.pangenx.com)
Any sufficiently advanced technology is indistinguishable from magic.

Vlad Patryshev

unread,
Aug 20, 2013, 2:33:23 PM8/20/13
to scala-l...@googlegroups.com
You have a bunch of nice simple answers already, with implicits (and that's what I do in practice... when forced to), but there's one observation.

Don't deal with booleans. There are two reasons at least. 1) boolean logic may be not always adequate to the real world outside; 2) you lose all the information pertaining to your data.

Better solutions could be match or subtyping. If you have a bar which represents not only the absence of data but also some idea about the nature of the absence, it might make sense to make it richer and supply it with functionality (beyond screaming "I have no data, poor me").

It may be a matter of taste of course; the shorter the code the better.

Thanks,
-Vlad


--

Manuel Bernhardt

unread,
Aug 21, 2013, 8:23:54 AM8/21/13
to scala-l...@googlegroups.com
Hi all,

thanks for the answers. In most cases in practice, when dealing with Options I am using an approach of the kind

    foo.map( useTheValue ).getOrElse( dealWithIt )

and am pretty happy with this (more so than if control-flow, or pattern matching).

The idea of the if ( optionBecomesBoolean ) comes from an observation from working more intensively with JavaScript, where this notation is really quite common and feels "natural". I know it can be implemented with implicit conversions, although I'm not sure I'd want to do that. My question could perhaps better be rephrased into "do you think this kind of notation would be something that could also feel natural in Scala", rather than how it can be achieved in practice. But as said, maybe it's more a matter of taste?

Manuel 

Alec Zorab

unread,
Aug 21, 2013, 8:30:31 AM8/21/13
to scala-l...@googlegroups.com
you may or may not care, but

X,map(f).getOrElse(g) === X.fold(g)(f)

Oliver Ruebenacker

unread,
Aug 21, 2013, 9:33:08 AM8/21/13
to scala-l...@googlegroups.com

     Hello,

  In C/C++, it is possible to write if(i), where i is int and 0 means false. I think I remember reading the advice that one should instead write if(i!=0) to be on the type-safer side.

  In Scala, if(myOption) will become confusing if myOption is Option[Boolean].

     Take care
     Oliver

Paul Phillips

unread,
Aug 22, 2013, 1:16:04 AM8/22/13
to scala-l...@googlegroups.com
On Tue, Aug 20, 2013 at 11:33 AM, Vlad Patryshev <vpatr...@gmail.com> wrote:
2) you lose all the information pertaining to your data.

I've come to see Boolean (and Int, etc.) as the moral equivalent of null. Bit patterns disassociated from meaning. It's barely an improvement on not using types at all. My usual example in this domain is Ordering.

trait Ordering[T] { def compare(x: T, y: T): Int }
 
We are defining a relation which admits three outcomes: LT, EQ, GT. So let's see, how to encode that. Let's choose a data type with 4294967296 states and say that by convention the first 2147483648 states mean LT, the next state means EQ, and the last 2147483647 states mean GT.

And THEN let's use the raw 32-bit pattern as the actual type, so that the values cannot be distinguished from any other 32-bit pattern. 5 monkeys, 5 trips to Cleveland, and GT, they're all completely interchangeable and indistinguishable.

If anyone proposed this in another context they'd be laughed out of the room. But we put up with this and worse, and there seems little demand to improve upon it, even though we have the power to do it without performance cost, or at least very nearly so. It makes me wonder if I should have hitched the trailer onto javascript.

Oliver Ruebenacker

unread,
Aug 22, 2013, 9:43:25 AM8/22/13
to scala-l...@googlegroups.com

     Hello,


On Thu, Aug 22, 2013 at 1:16 AM, Paul Phillips <pa...@improving.org> wrote:

On Tue, Aug 20, 2013 at 11:33 AM, Vlad Patryshev <vpatr...@gmail.com> wrote:
2) you lose all the information pertaining to your data.

I've come to see Boolean (and Int, etc.) as the moral equivalent of null. Bit patterns disassociated from meaning. It's barely an improvement on not using types at all. My usual example in this domain is Ordering.

  What is wrong with Boolean? Booleans are an algebra. Don't we love algebras?

  On a practical level, what would you do instead of this:

  def todayIsWorkDay : Boolean = ! (todayIsSunday | todayIsHoliday)


trait Ordering[T] { def compare(x: T, y: T): Int }
 
We are defining a relation which admits three outcomes: LT, EQ, GT. So let's see, how to encode that. Let's choose a data type with 4294967296 states and say that by convention the first 2147483648 states mean LT, the next state means EQ, and the last 2147483647 states mean GT.

And THEN let's use the raw 32-bit pattern as the actual type, so that the values cannot be distinguished from any other 32-bit pattern. 5 monkeys, 5 trips to Cleveland, and GT, they're all completely interchangeable and indistinguishable.

If anyone proposed this in another context they'd be laughed out of the room. But we put up with this and worse, and there seems little demand to improve upon it, even though we have the power to do it without performance cost, or at least very nearly so. It makes me wonder if I should have hitched the trailer onto javascript.

  Obviously, a three-state type is preferable. I'm assuming this particular example is left-over baggage from Java (or even C++) history when there was no efficient alternative. If this can be done with no performance penalty, sounds great. How would that look like?

 I don't see how that is a failure of Int in general. Can't I abuse other types similarly? I love Int. Besides, why do you say Int is a raw 32-bit pattern? Looks like a range of integers to me.

     Take care
     Oliver

Haoyi Li

unread,
Aug 22, 2013, 10:47:56 AM8/22/13
to scala-l...@googlegroups.com
I've come to see Boolean (and Int, etc.) as the moral equivalent of null. Bit patterns disassociated from meaning. It's barely an improvement on not using types at all.

+1 to this. paulp detailed what's wrong with using booleans as an output type in your API, but using them as an input type is just as silly. I almost *never* need to use boolean flags in the way that's common in languages like C/java/javascript. There's almost always a better way.

A sort function with sort(reversed=true)? Why not just pass in the comparison function and sort by any metric you want.

compile(writeToFilesystem=true)? Why not pass in a (AbstractFile) => () function and let it write anywhere.

logging=true? Why not pass in a proper logging function (String => ()) so I can redirect the logging where ever without messing with your nasty log4J configuration.

The list goes on; Booleans as an input flag basically means "I wrote two completely separate programs in one function, so pick one". 

> I don't see how that is a failure of Int in general. Can't I abuse other types similarly? 

Of course you can. People abuse Boolean all the time too. And Strings too. I used to use Chars to define my AI state machines, because 'a' *obviously* means "attack"!



Paul Phillips

unread,
Aug 22, 2013, 11:36:18 AM8/22/13
to scala-l...@googlegroups.com

On Thu, Aug 22, 2013 at 7:47 AM, Haoyi Li <haoy...@gmail.com> wrote:
+1 to this. paulp detailed what's wrong with using booleans as an output type in your API, but using them as an input type is just as silly.


On Sun, Apr 29, 2012 at 8:32 AM, martin odersky <martin....@epfl.ch> wrote: 
> I agree, and that's what code review needs to guard against. 

Why do I want another thing to guard against? Why does the rest of the 
world? (We are talking about boolean arguments *in API* which implies 
inflicting this guarding requirement on everyone.) 

Although it is tempting to burn off some time writing the complete 
case against Boolean parameters, I can't bear to use my time that way 
right now.  Suffice to say that it would be a lengthy screed.  Using 
booleans to partition behavior among a small set of discrete 
alternatives means you forego using one of the best features of 
objects - polymorphic dispatch - in order to drizzle your code with 
meaningless one-bit carriers.  Here's a sample type signature, what 
does this tell us? 

  (Type, Boolean, Boolean) => Type 

When you use polymorphism, you don't have to start tacking those 
Booleans on as meaningless appendages when you realize you need access 
to b in method g.  Nor do you find yourself with "invalid states" when 
you have three states to cover, and you need the booleans to arrive 
true/true, true/false, and false/true, but false/false means nothing. 
When you use polymorphism, you already encapsulated data and behavior. 
 You can extend. 

I do recall a before/after where I expunged boolean parameters. 


Samples of the "before" code: 

-        case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => 
-          path(true, false) 
... 
-            t = (t /: annotations(false, false)) (makeAnnotated) 
... 
-          params += typeParam(NoMods.withAnnotations(annotations(true, false))) 

Now we can say they should have used named parameters on those trues 
and falses until we're blue in the face (even if they didn't exist 
yet, doesn't matter) and it won't make the names appear.  But even if 
we could count on everyone doing that, it's still worse.  Booleans 
ring of the arbitrary.  There's always a better type signature than 
(X, Boolean, Boolean) => Y to communicate what is taking place.  Have 
some pity on the guy who has to read the code. 


Oliver Ruebenacker

unread,
Aug 22, 2013, 11:43:59 AM8/22/13
to scala-l...@googlegroups.com

     Hello,

  Why no one made a suggestion on how to re-write:


def todayIsWorkDay : Boolean = ! (todayIsSunday | todayIsHoliday)

     Take care
     Oliver



--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Oliver Ruebenacker
IT Project Lead at PanGenX (http://www.pangenx.com)
Be always grateful, but never satisfied.

Bardur Arantsson

unread,
Aug 22, 2013, 11:51:57 AM8/22/13
to scala-l...@googlegroups.com
On 2013-08-22 17:43, Oliver Ruebenacker wrote:
> Hello,
>
> Why no one made a suggestion on how to re-write:
>
> def todayIsWorkDay : Boolean = ! (todayIsSunday | todayIsHoliday)
>

Unless I'm missing something it looks pretty trivial to me:

sealed abstract trait WorkDayOrNot
case object WorkDay extends WorkDayOrNot
case object Holiday extends WorkDayOrNot

def todayIsWorkDay : WorkDayOrNot =
(fill in implementation yourself)

Regards,


Lex Spoon

unread,
Aug 22, 2013, 11:54:03 AM8/22/13
to scala-l...@googlegroups.com
On Thu, Aug 22, 2013 at 11:43 AM, Oliver Ruebenacker <cur...@gmail.com> wrote:
>
> Hello,
>
> Why no one made a suggestion on how to re-write:
>
>
> def todayIsWorkDay : Boolean = ! (todayIsSunday | todayIsHoliday)

The simplest better thing to do is to make an enum for it.


sealed abstract class WorkDayKind
case object WorkDay extends WorkDayKind
case object Holiday extends WorkDayKind
case object WeekendDay extends WorkDayKind

...
def workDayKind: WorkDayKind


It's more code, but it's code that is easier to maintain. Of course
it's a judgment call when to make the leap, but if you are working on
code that is any sort of time-consuming and non-trivial, then this
sort of transformation looks very helpful for getting it shaped up and
more robust.

Lex Spoon

Lex Spoon

unread,
Aug 22, 2013, 11:55:56 AM8/22/13
to scala-l...@googlegroups.com
On Thu, Aug 22, 2013 at 11:51 AM, Bardur Arantsson <sp...@scientician.net> wrote:
> Unless I'm missing something it looks pretty trivial to me:
>
> sealed abstract trait WorkDayOrNot

Jinx!

Paul Phillips

unread,
Aug 22, 2013, 11:57:04 AM8/22/13
to scala-l...@googlegroups.com

On Thu, Aug 22, 2013 at 8:54 AM, Lex Spoon <l...@lexspoon.org> wrote:
It's more code, but it's code that is easier to maintain.

Also, when considering this question we should strongly distinguish between abstraction and implementation. scala inflicts a ton of boilerplate on you to define a 2 or 3 state enum, but that tells us nothing about the wisdom of using more meaningful types than "Boolean".


Oliver Ruebenacker

unread,
Aug 22, 2013, 12:01:28 PM8/22/13
to scala-l...@googlegroups.com

     Hello,

  So, instead of

  if(todayIsWorkDay) wakeMeUp

  I would then have to use something with isInstanceOf or match?

     Take care
     Oliver



--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Simon Ochsenreither

unread,
Aug 22, 2013, 12:36:28 PM8/22/13
to scala-l...@googlegroups.com

Also, when considering this question we should strongly distinguish between abstraction and implementation. scala inflicts a ton of boilerplate on you to define a 2 or 3 state enum, but that tells us nothing about the wisdom of using more meaningful types than "Boolean".

@enum class WorkDayKind { WorkDay; Holiday; WeekendDay }

Hey, I'm kind of trying to change that. :-)
If you like, maybe you could share your opinion on some of the remaining questions: https://groups.google.com/d/msg/scala-language/C7Pm6ab1sPs/-BoEfECjsx8J

I would really appreciate that. Especially the ConstantType thing in Namers/Constructors looks a lot like a hack to me, but maybe you have more insight here.

(Sorry to jump into this ...)

Lex Spoon

unread,
Aug 22, 2013, 12:48:29 PM8/22/13
to scala-l...@googlegroups.com
On Thu, Aug 22, 2013 at 12:01 PM, Oliver Ruebenacker <cur...@gmail.com> wrote:
>
> Hello,
>
> So, instead of
>
> if(todayIsWorkDay) wakeMeUp
>
> I would then have to use something with isInstanceOf or match?

If there are only two cases, you can use ==. -Lex

Bardur Arantsson

unread,
Aug 22, 2013, 1:02:34 PM8/22/13
to scala-l...@googlegroups.com
Yeah, but IIRC that doesn't warn in case you've introduced a new case
which should be matched, so personally, I'd _generally_ recommend a
pattern match. (Applies only to _sealed_ case classes, obviously.)

In this concrete case it's quite unlikely that there's going to be some
change in specs that'll require expanding "IsItAWorkDayOrNot", so I
guess you might as well use ==. :)

Regards,


Som Snytt

unread,
Aug 22, 2013, 1:21:57 PM8/22/13
to scala-l...@googlegroups.com
> it's quite unlikely that there's going to be some change in specs that'll require expanding "IsItAWorkDayOrNot"

You might have to localize your application for France.



Bardur Arantsson

unread,
Aug 22, 2013, 1:42:41 PM8/22/13
to scala-l...@googlegroups.com
On 2013-08-22 19:21, Som Snytt wrote:
>> it's quite unlikely that there's going to be some change in specs that'll
> require expanding "IsItAWorkDayOrNot"
>
> You might have to localize your application for France.
>

Do they have more states than

a) "it's a work day", and
b) "it's not a work day"

?

Paul Phillips

unread,
Aug 22, 2013, 2:15:51 PM8/22/13
to scala-l...@googlegroups.com

On Thu, Aug 22, 2013 at 10:42 AM, Bardur Arantsson <sp...@scientician.net> wrote:
Do they have more states than

  a) "it's a work day", and
  b) "it's not a work day"

Come on, we're talking about France. Of course they do.

"France: Booleans with nuance!"


Andrew Phillips

unread,
Aug 22, 2013, 2:40:52 PM8/22/13
to scala-l...@googlegroups.com
> Come on, we're talking about France. Of course they do.

Booléans?

ap

Rich Oliver

unread,
Aug 22, 2013, 3:17:21 PM8/22/13
to scala-l...@googlegroups.com
On Thursday, August 22, 2013 6:16:04 AM UTC+1, Paul Phillips wrote:

I've come to see Boolean (and Int, etc.) as the moral equivalent of null.

I'm very glad to hear it. Personally I see syntactic anorexia and keyword asceticism as the source of much of Scala's moral degeneracy.

Bardur Arantsson

unread,
Aug 22, 2013, 5:35:14 PM8/22/13
to scala-l...@googlegroups.com
Wait, what was this thread about again? :)

Regards,


Rex Kerr

unread,
Aug 22, 2013, 6:37:01 PM8/22/13
to scala-l...@googlegroups.com
On Thu, Aug 22, 2013 at 11:36 AM, Paul Phillips <pa...@improving.org> wrote:

On Thu, Aug 22, 2013 at 7:47 AM, Haoyi Li <haoy...@gmail.com> wrote:
+1 to this. paulp detailed what's wrong with using booleans as an output type in your API, but using them as an input type is just as silly.

I can offer that one also, enclosed below: https://groups.google.com/forum/#!msg/scala-internals/5VhsT3PhcSg/MWuqSJieVeYJ

Using 
booleans to partition behavior among a small set of discrete 
alternatives means you forego using one of the best features of 
objects - polymorphic dispatch - in order to drizzle your code with 
meaningless one-bit carriers.  Here's a sample type signature, what 
does this tell us? 

  (Type, Boolean, Boolean) => Type

It tells me not that we shouldn't use booleans but that type systems aren't enough metadata about your problem.

(Type, Boolean \ Cached, Boolean \ SeekOnDisk) => Type

would tell an awful lot more (where I'm pretending that \ Blah specifies the unit is Blah).

But a normal type system is stupendously arduous for this sort of thing, for two reasons.  First, it inflicts upon you an enormous burden for duplicating Boolean and the like over and over again.  It's not DRY at all, it's RYOAOA (repeat yourself over and over again).  The logic of Boolean is perfect.  The problem is that you need something equivalent to units of measurement to keep straight what kind of thing that boolean was talking about.
 

When you use polymorphism, you don't have to start tacking those 
Booleans on as meaningless appendages when you realize you need access 
to b in method g.  Nor do you find yourself with "invalid states" when 
you have three states to cover, and you need the booleans to arrive 
true/true, true/false, and false/true, but false/false means nothing. 

You need a single trinary state, not fifty different implementations of the same thing, some with addition and some with multiplication and some with neither.  Integers with ranges are great, but there should be only one: [-1,1].
 
When you use polymorphism, you already encapsulated data and behavior. 
 You can extend. 

I do recall a before/after where I expunged boolean parameters. 


Samples of the "before" code: 

-        case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => 
-          path(true, false) 
... 
-            t = (t /: annotations(false, false)) (makeAnnotated) 
... 
-          params += typeParam(NoMods.withAnnotations(annotations(true, false))) 

Now we can say they should have used named parameters on those trues 
and falses until we're blue in the face (even if they didn't exist 
yet, doesn't matter) and it won't make the names appear.

That's because they're not units.  Meters aren't kilowatts.
 
I just don't think type systems--not even in languages like Haskell and Agda--really capture the idea of units of measurement well.  Yes, yes, you can perfectly well emulate them with appropriate wrappers and all, but that's rather like having to explicitly declare a new class every time you want to use a closure: thanks, but all that extra work makes it not worth it any more.

For example, compare these:

def fft(xs: Array[Float], inplace: Boolean): Array[Float]

sealed trait Placement
final object InPlace extends Placement
final object Allocate extends Placement
def fft(xs: Array[Float], inplace: Placement): Array[Float]

unit InPlace = Boolean
def fft(xs: Array[Float], ip: Boolean \ InPlace): Array[Float]

The middle option is just atrocious.  Let's be inspired by Haskell syntax:

type Placement = InPlace | Allocate
def fft(xs: Array[Float], inplace: Placement): Array[Float]

But now suppose we want to only do something in place if neither of two others have been in place:

  val p = if (p1==InPlace || p2==InPlace) Allocate else InPlace

compared to

  val p = !(p1 || p2)

I suppose if you really like reading the first one is better?  And do you see how we now have three names cluttering our namespace when one was fully adequate to describe what was going on?

And now at the use site:

  val a = fft(z, true)
  val b: Boolean = f()
  val c = fft(y, b)

  val a = fft(z, InPlace)
  val b: Placement = f()
  val c = fft(y, b)

  val a = fft(z, true \ InPlace)
  val b: InPlace = f()
  val c = fft(y, b)

the first one is not really any help (true what?!).  The other two tell you what, but the standard enum/etc. thing requires you to remember that "Placement" means "InPlace" while the units version (assuming you're allowed to shortcut by just specifying the unit when the type is implied by the unit) names exactly the one thing you care about.

Finally, let's assume that you will just extend or wrap boolean:

class InPlace extends Boolean
val b: InPlace = true   // Argh, doesn't work, true is not an InPlace

case class InPlace(val value: Boolean) extends AnyVal {}
implicit def unwrapInPlace(ip: InPlace): Boolean = ip.value
def fft(xs: Array[Float], ip: InPlace): Array[Float]
val p = InPlace( !(p1 || p2) )
val a = fft(z, InPlace(true))
val b: InPlace = f()
val c = fft(y,b)

Well, okay, not too shabby, even if it is a lot of boilerplate.  But it's only part of a solution.

case class Meters(val value: Double) extends AnyVal {}
// Meters must be Double?  *sigh*...if you insist.

def area(x: Meters, y: Meters) = Meters( Meters( x.value * y.value ) )
// Good luck with that.

  --Rex


Paul Phillips

unread,
Aug 22, 2013, 7:21:06 PM8/22/13
to scala-l...@googlegroups.com
I don't care to discuss the boilerplate requirements in scala or other languages. I know this can be expressed by the programmer and enforced in a type system without it being some kind of redundancy tragedy. We know how to reuse behavior. We know how to distinguish different things when there is value in doing so. All we have to do is do it.

Rex Kerr

unread,
Aug 22, 2013, 8:05:35 PM8/22/13
to scala-l...@googlegroups.com
I think it would be great to do it.  But I don't think it's going to look like a normal part of a type system, or rather, if it does, it would solve one portion of a problem that is better expressed using a different framework.

In particular, units are much happier being completely a compiler fiction than are the current system of value types.  If units are flat, it lets you escape all sorts of variance complexity.  If units can tag anything, you can invent and specify use-cases at will for free.  Computation of units is vastly easier than computing types.  Tagging sealed/final classes with types is not a problem.

I'm not saying that a more powerful and less baggage-heavy interface to the type system wouldn't be nice as well.  But I have trouble envisioning how some things which are nigh-trivial with units wouldn't require extreme mastery of any more general type system to accomplish.

For example:

  class X[A](a: A\A) {
    def +(aa: A\A): A\A = foo(a, aa)
    def *[\B](ab: A\B): A\A\B = bar(a, ab)
    def /[\C](ac: A\C): A\A\C[-1] = baz(a, ac)
  }

would be enough to express the normal mathematical relationships with units.

Want to make sure your builder builds all its pieces before giving you a correct one?

unit Named
unit Aged
class Buildable {
  var name = ""
  var age = 0
  def setName(n: String): this.type\this\Named = { name = n; this: this\Named }
  def setAge(a: Int): this.type\this\Aged = { age = a; this: this\Aged }
}
type Built = Buildable\Named[0<]\Aged[0<]

Maybe the syntax can use some work, but there's a lot of stuff you can do with keeping track of lightweight int-indexed tags, and the only reason you don't get tripped up with massive complexity is that they are just lightweight int-indexed tags.

  --Rex



On Thu, Aug 22, 2013 at 7:21 PM, Paul Phillips <pa...@improving.org> wrote:
I don't care to discuss the boilerplate requirements in scala or other languages. I know this can be expressed by the programmer and enforced in a type system without it being some kind of redundancy tragedy. We know how to reuse behavior. We know how to distinguish different things when there is value in doing so. All we have to do is do it.

--

Som Snytt

unread,
Aug 23, 2013, 2:07:47 AM8/23/13
to scala-l...@googlegroups.com
I got tired of flags like f(ok=true), so for some time now I only use:

    sealed trait OK_?
    case object \u1f44d extends OK_?
    case object \u1f44e extends OK_?


http://www.charbase.com/1f44d-unicode-thumbs-up-sign




--

Jan Vanek

unread,
Aug 23, 2013, 5:00:05 AM8/23/13
to scala-l...@googlegroups.com
http://www.boost.org/doc/libs/1_54_0/libs/mpl/doc/tutorial/dimensional-analysis.html

I'm sure you know that Rex. But since it's one of AHA moments of Scott Meyers I thought it's worth posting.

Oliver Ruebenacker

unread,
Aug 23, 2013, 8:13:55 AM8/23/13
to scala-l...@googlegroups.com

     Hello,

  I would also strongly argue that trying to find the perfect type for every argument or return value will lead to an enormous overhead of type declarations but even more so type conversions (especially from XinLibraryA to XinLibraryB) and will lead to code such as:

  if(statusOfX.to[CanBePerformedSafely].to[Boolean]) doX

  There will be development cycles that go like this:
    (1) Slightly different types will be introduced
    (2) We need to convert between these slightly different types
    (3) Conversion needs to be consistent
    (4) The slightly different types will become more and more the same

  I am very wary of introducing something called "units". The name suggests inspiration from units of measurement. Formalizing units of measurement is an endeavor that seems deceptively simple and turns out extremely hard. Attempts to list all units begin with the obvious ones (metre, kilogram, second) and eventually descend into obscurities for the sake of completeness (such as "size of disk" in the Unit Ontology). Particularly controversial is, for example, the question whether "10 water molecules" should be considered (a) dimensionless or (b) of dimension "molecules" or (c) of dimension "water molecules". There are strong arguments for each choice.

  Types should be compromises covering many cases, rather than perfect solutions for each single case, since values need to move across concerns.

     Best,
     Oliver


--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Rex Kerr

unread,
Aug 23, 2013, 8:31:49 AM8/23/13
to scala-l...@googlegroups.com
On Fri, Aug 23, 2013 at 8:13 AM, Oliver Ruebenacker <cur...@gmail.com> wrote:

     Hello,

  I would also strongly argue that trying to find the perfect type for every argument or return value will lead to an enormous overhead of type declarations but even more so type conversions (especially from XinLibraryA to XinLibraryB) and will lead to code such as:

  if(statusOfX.to[CanBePerformedSafely].to[Boolean]) doX

  There will be development cycles that go like this:
    (1) Slightly different types will be introduced
    (2) We need to convert between these slightly different types
    (3) Conversion needs to be consistent
    (4) The slightly different types will become more and more the same

  I am very wary of introducing something called "units". The name suggests inspiration from units of measurement. Formalizing units of measurement is an endeavor that seems deceptively simple and turns out extremely hard.

The point is a separation between tags that describe how something should be used, and between functionality which is generic.

We already do that with variable names, except careful naming doesn't let the compiler warn us we're making a mistake; a units system would.

The basic rules of dimensional analysis are not extremely hard.  Deciding how to separate the natural world into things with units is hard, granted, but we don't need to be complete to be useful.

  --Rex

Nils Kilden-Pedersen

unread,
Aug 23, 2013, 9:36:31 AM8/23/13
to scala-l...@googlegroups.com

On Thu, Aug 22, 2013 at 10:43 AM, Oliver Ruebenacker <cur...@gmail.com> wrote:


     Hello,

  Why no one made a suggestion on how to re-write:


def todayIsWorkDay : Boolean = ! (todayIsSunday | todayIsHoliday)

It's kind of a bad example, because “work day” is not a boolean property. There are half work days also.

With that said, I think Boolean parameters are worse than Boolean return values. I don't think anyone seriously would want all the Boolean return values on the collections library to be enums or the like, e.g. contains, isEmpty, etc.

Erik Osheim

unread,
Aug 22, 2013, 12:47:01 PM8/22/13
to scala-l...@googlegroups.com
On Thu, Aug 22, 2013 at 12:01:28PM -0400, Oliver Ruebenacker wrote:
> So, instead of
>
> if(todayIsWorkDay) wakeMeUp
>
> I would then have to use something with isInstanceOf or match?

Unless wakeMeUp is used solely for side-effects (and you throw away
its return value) this code doesn't make sense, right? So we're really
talking about something like:

if (todayIsWorkDay) wakeMeUp else keepSleeping

This might end up looking like:

todayIsWorkDay match {
case WorkDay => wakeMeUp
case _ => keepSleeping
}

or:

todayIsWorkDay.fold(wakeMeUp, keepSleeping, keepSleeping)

or:

todayIsWorkDay.ifWork(wakeMeUp, keepSleeping)

or something similar. The big advantage in this case is that if you
mistakenly think that there's only "work day" and "Sunday" categories,
the fold/pattern match may remind you to handle the third case.

I don't think I take this as far as Paul does--I don't mind defining
filter(f: A => Boolean): C[A] for instance. But I do think that
Booleans make incredibly poor arguments to functions, and often make
poor return values as well.

To be clear, the main drawback of Boolean return values is the
following doomsday scenario:

val lunch = isTimeToHaveLunch()
val launch = isTimeToLaunchMissiles()

// 2,394 lines of code later...

if (lunch) launchTheMissiles() else standDownMissiles()

Oops. This one-character typo will definitely not be caught at
compile-time, despite the fact that the answer to whether or not to go
out for sandwiches is (hopefully) very different than ending life on
the planet.

-- Erik

Shelby

unread,
Sep 14, 2013, 11:22:15 PM9/14/13
to scala-l...@googlegroups.com
As someone else pointed out upthread, you may need the value too. In my language, there is syntax if foo? {...} where inside the block foo has the value implemented by match case Some(foo) =>.

Rich Oliver

unread,
Sep 17, 2013, 10:22:36 AM9/17/13
to scala-l...@googlegroups.com
Just give us time, distance and velocity! I bet that would cover a huge percentage of use cases Actually we've already got a decent time in Java8, hopefully it can be suitably wrapped. So its just a case of a Standard library distance classes and to make them work with time to produce velocities.

Shelby

unread,
Sep 17, 2013, 9:51:06 PM9/17/13
to scala-l...@googlegroups.com, sp...@scientician.net
Re: the OP, besides the sugar for, foo match{ case Some(a) => ... }, there is also a request for sugar for the None case:


Perhaps for my language I will offer, if !foo? { ... } as a sugar for, if foo is None { ... }, although the latter reads more clearly.

More below...
That code is only surely valid never, because after you run it, it might be tomorrow. That is an example of the problem with Boolean, it throws away information. 

Functional alternative:

class WorkDay(a: Date) extends Date(a)

implicit def someWorkDay(a: Date): Option[WorkDay] = WorkDay(a)

object WorkDay {
   def apply(a: Date): Option[WorkDay] = if ((a: Option[Sunday]).IsInstanceOf[Some[Sunday]] || (a: Option[Holiday]).IsInstanceOf[Some[Holiday]]) None else Some(a)
   def unapply(a: Option[WorkDay]) = a
}

(the class and object for Sunday and Holiday are not shown and follow the same pattern)

Thus anonymous function which inputs Date or Option[WorkDay], (_: Option[WorkDay]) match { case WorkDay(workday) => ... case _ => ... }

Of in my language that could be shortened, if (_1: Option[WorkDay])? { ... // _1 is now a WorkDay } else ...

Note the above is a general pattern to avoid throwing exceptions, where there is some validation that must be done before a type can be constructed from another type, e.g. constructing a UInt from an Int.

On Friday, August 23, 2013 12:48:29 AM UTC+8, lexspoon wrote:
On Thu, Aug 22, 2013 at 12:01 PM, Oliver Ruebenacker <cur...@gmail.com> wrote: 

>      Hello, 

>   So, instead of 

>   if(todayIsWorkDay) wakeMeUp 

>   I would then have to use something with isInstanceOf or match? 

If there are only two cases, you can use ==.  -Lex 
 
I don't understand. Where is that special case documented?
Reply all
Reply to author
Forward
0 new messages