This page is no longer maintained — Please continue to the home page at www.scala-lang.org

RE: Optional parameters (a language proposal)

No replies
Ryan Hendrickson
Joined: 2012-02-01,
User offline. Last seen 42 years 45 weeks ago.

> On 07/02/12 12:12, Ryan Hendrickson wrote:
> >> f(t: Option[T])
> >> g(t: T) = f(Some(t))
> >> h = f(None)
> >>
> >> I do it all the time. It is the most appropriate solution. Objectors
> to
> >> the new function names may like to take note that they are very
> >> different functions; as different as any others.
> > Doesn't scale. Is this the most appropriate solution:
> >
> > class GuiWidget(backgroundColor: Option[Color], foregroundColor:
> Option[Color], fontFamily: Option[String], fontSize: Option[Int])
> >
> > def makeWidget = new GuiWidget(None, None, None, None)
> > def makeWidgetWithBG(bg: Color) = new GuiWidget(Some(bg), None,
> None, None)
> > def makeWidgetWithFG(fg: Color) = new GuiWidget(None, Some(fg),
> None, None)
> > def makeWidgetWithBGAndFG(bg: Color, fg: Color) = new
> GuiWidget(Some(bg), Some(fg), None, None)
> > // and twelve* more very different functions...
> >
> > This is a real problem, I think. Workarounds exist but none of them
> are elegant, and ignoring the problem by just passing in Options all the
> time is safe but obnoxiously redundant. I'm proposing a way for Scala to
> do better, reusing patterns and concepts already in the language, and
> without (I think) sacrificing much if any clarity or purity. I'm not
> completely sure from your email that you disagree with any of this, but
> if so, I'd like to hear you (or any lurking naysayer) explain why.
> >
> > ---
> >
> > (*) And that's not even counting combinations of lifted and unlifted
> parameters, like
> >
> > def
> makeWidgetWithOptionalFGAndFontFamilyAndFontSize(foregroundColor:
> Option[Color], fontFamily: String, fontSize: Int)
> >
> > I don't think any reasonable person would propose defining all 81
> combinations of {present, absent, Option'd}^4, but just remember that
> you essentially get all of them for the price of one with _? syntax,
> with the same mechanics that Scala users already have an intuition for
> with _*, and with none of the ambiguity that comes with various implicit
> workarounds.)
> >
> So, the problem I have with this argument is that I find it is
> indistinguishable from saying, "having many functions does not scale",
> then proceed to demonstrate that there exist many possible functions.
> The counter-argument to this is that these particular functions related
> to Option deserve special significance above any other, regular,
> distinct, completely distinct, different, unrelated functions. I argue
> that no such special significance is deserved. This is what I mean when
> I say, "take note that they are very different functions; as different
> as any others."
>
> By different here, I mean unrelated in any meaningful way. I have never
> seen it explained in a way that provides that meaning. Handwaving it
> away under the assumption that this significance is deserved by
> credulity, then proclaiming "doesn't scale" it not compelling -- not
> that I think you are doing this -- but I have seen it and I hope to
> avoid that situation so I mention it only for that reason.
>
> By the way, there is actually a really neat solution to improving the
> practical implications of this situation, but not in the general case,
> which is all we are discussing at this point.

Okay, good, thanks for clarifying. The 'very different' remark makes more sense now.

Let me start by pointing out that, in case the text of my proposal was too long-winded or not clear enough, I am not talking about changing the rules for every function that takes an Option as a parameter. You don't just get to walk up to a function that takes an Option[A] and treat it like it takes an A. The analogy is with the * in

def foo(values: Int*): String

Having that feature doesn't mean that every function that takes a Seq can be used with varargs syntax.

Imagine a Scala without *, temporarily. If you proposed adding it, and I were to reply that I work around this with

def f(t: Seq[T])
def g = f(Nil)
def h(t0: T) = f(t0 :: Nil)
def i(t0: T, t1: T) = f(t0 :: t1 :: Nil)

and thus don't see a need for *, I think it would be somewhat missing the point to talk about g, h, and i all being different unrelated functions (unless I am still misunderstanding your remark). Of course they are distinct, but the point is about making f simpler to call with less boilerplate syntactic baggage in the common case, not about any relations that might exist between functions constructed to work around the problem. Certainly not all functions that take a Seq benefit from using a * instead. But the ones that do, really do.

(Now that's not quite fair, obviously, because each * parameter would need to be supported by an infinite number of overloads in the absence of * to really get an equivalent effect, whereas as you and I have both demonstrated, the number required to match the behavior of a ? parameter is at least finite (though exponential in the count of such parameters). And also there are additional Java-compatibility reasons for supporting varargs. So certainly having ? is not as important as *. In my experience, though, uses for this feature would still be pretty common.)

We already have something that comes very close to removing this baggage: default arguments. But to use default arguments, the implementation of your function f: Option[A] => B must satisfy f(None) == f(a_def) for some (possibly computed) a_def in A, so that you can write f as

def f(a: A = a_def): B

The proposal is 50% just a clean way to remove that implementation restriction. (The other 50% is about what you give up when you rewrite f: Option[A] => B in this way, whether you use today's default arguments to do it or the proposed ? syntax: the ability to actually pass in an Option[A] when that's what you have, and not have to treat f like it actually is two distinct functions that you call in two branches of a fold-like control structure.)

----------------------------------------

This message is intended exclusively for the individual(s) or entity to
which it is addressed. It may contain information that is proprietary,
privileged or confidential or otherwise legally exempt from disclosure.
If you are not the named addressee, you are not authorized to read,
print, retain, copy or disseminate this message or any part of it.
If you have received this message in error, please notify the sender
immediately by e-mail and delete all copies of the message.

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