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

Re: type of "if (x) Foo"

9 replies
DRMacIver
Joined: 2008-09-02,
User offline. Last seen 42 years 45 weeks ago.

On Sat, Mar 14, 2009 at 11:34 AM, David MacIver wrote:
> On Sat, Mar 14, 2009 at 7:26 AM, David Pollak
> wrote:
>>
>>
>> On Sat, Mar 14, 2009 at 3:51 AM, Paul Phillips wrote:
>>>
>>> On Sat, Mar 14, 2009 at 06:04:31AM +0300, Stepan Koltsov wrote:
>>> > I haven't read the start of the discussion :) Changing type of if to
>>> > Any is bad. Don't you know what is motivation behind that change?
>>>
>>> I don't know.  I should clarify, it actually expands to
>>>
>>>  if (cond) x else ()
>>
>> I'm guessing that this is to make:
>>
>> {
>>   if (baz) "bar"
>> }
>>
>> Behave as some people expect it to.  I'm not keen on either change.  From a
>> "newbie mistake with XML" standpoint, the change on trunk makes more sense.
>>  From a purish FP standpoint, a partially applied if is kinda amusing.  I
>> would hope that one would optimize it such that it would only create the
>> Some() in the case of assignment or generation of a return value.
>
> There's actually a very compelling reason for the trunk version: Tail
> call optimisation doesn't work with the version as it stands in 2.7.3
>
> def kittens(n : Int) = { println("Kittens!"); if (kittens > 0) kittens(n - 1) }
>
> I'm not sure what this used to translate to, but in 2.7.3 this will
> stack overflow given enough kittens whileas, in trunk it won't.
>

Note that this works just as well with the Option version. It's a
compelling reason for either of them in preference to the existing
behaviour, not for the trunk behaviour vs. Option.

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: type of "if (x) Foo"
It wouldn't work in the Option case without extra compiler magic. In:

   def kittens(n : Int): Option[Unit] = { println("Kittens!"); if (kittens > 0) kittens(n - 1) }

You'd get a type mismatch because the return type of kittens(n - 1) is Option[Unit], so the return type of if(kittens > 0) kittens(n - 1) would be Option[Option[Unit]], which wouldn't conform to kitten's type signature.

--j

On Sat, Mar 14, 2009 at 4:34 AM, David MacIver <david [dot] maciver [at] gmail [dot] com> wrote:
On Sat, Mar 14, 2009 at 11:34 AM, David MacIver <david [dot] maciver [at] gmail [dot] com> wrote:
> On Sat, Mar 14, 2009 at 7:26 AM, David Pollak
> <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:
>>
>>
>> On Sat, Mar 14, 2009 at 3:51 AM, Paul Phillips <paulp [at] improving [dot] org> wrote:
>>>
>>> On Sat, Mar 14, 2009 at 06:04:31AM +0300, Stepan Koltsov wrote:
>>> > I haven't read the start of the discussion :) Changing type of if to
>>> > Any is bad. Don't you know what is motivation behind that change?
>>>
>>> I don't know.  I should clarify, it actually expands to
>>>
>>>  if (cond) x else ()
>>
>> I'm guessing that this is to make:
>> <foo>
>> {
>>   if (baz) "bar"
>> }
>> </foo>
>> Behave as some people expect it to.  I'm not keen on either change.  From a
>> "newbie mistake with XML" standpoint, the change on trunk makes more sense.
>>  From a purish FP standpoint, a partially applied if is kinda amusing.  I
>> would hope that one would optimize it such that it would only create the
>> Some() in the case of assignment or generation of a return value.
>
> There's actually a very compelling reason for the trunk version: Tail
> call optimisation doesn't work with the version as it stands in 2.7.3
>
> def kittens(n : Int) = { println("Kittens!"); if (kittens > 0) kittens(n - 1) }
>
> I'm not sure what this used to translate to, but in 2.7.3 this will
> stack overflow given enough kittens whileas, in trunk it won't.
>

Note that this works just as well with the Option version. It's a
compelling reason for either of them in preference to the existing
behaviour, not for the trunk behaviour vs. Option.

Alex Boisvert
Joined: 2008-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: type of "if (x) Foo"

Just an idea, maybe this form:

if (foo) yield bar

could produce Option[Bar]. With no else clause allowed.

alex

On 3/14/09, Jorge Ortiz wrote:
> It wouldn't work in the Option case without extra compiler magic. In:
>
> def kittens(n : Int): Option[Unit] = { println("Kittens!"); if (kittens >
> 0) kittens(n - 1) }
>
> You'd get a type mismatch because the return type of kittens(n - 1) is
> Option[Unit], so the return type of if(kittens > 0) kittens(n - 1) would be
> Option[Option[Unit]], which wouldn't conform to kitten's type signature.
>
> --j
>
> On Sat, Mar 14, 2009 at 4:34 AM, David MacIver
> wrote:
>
>> On Sat, Mar 14, 2009 at 11:34 AM, David MacIver
>> wrote:
>> > On Sat, Mar 14, 2009 at 7:26 AM, David Pollak
>> > wrote:
>> >>
>> >>
>> >> On Sat, Mar 14, 2009 at 3:51 AM, Paul Phillips
>> wrote:
>> >>>
>> >>> On Sat, Mar 14, 2009 at 06:04:31AM +0300, Stepan Koltsov wrote:
>> >>> > I haven't read the start of the discussion :) Changing type of if to
>> >>> > Any is bad. Don't you know what is motivation behind that change?
>> >>>
>> >>> I don't know. I should clarify, it actually expands to
>> >>>
>> >>> if (cond) x else ()
>> >>
>> >> I'm guessing that this is to make:
>> >>
>> >> {
>> >> if (baz) "bar"
>> >> }
>> >>
>> >> Behave as some people expect it to. I'm not keen on either change.
>> From a
>> >> "newbie mistake with XML" standpoint, the change on trunk makes more
>> sense.
>> >> From a purish FP standpoint, a partially applied if is kinda amusing.
>> I
>> >> would hope that one would optimize it such that it would only create
>> >> the
>> >> Some() in the case of assignment or generation of a return value.
>> >
>> > There's actually a very compelling reason for the trunk version: Tail
>> > call optimisation doesn't work with the version as it stands in 2.7.3
>> >
>> > def kittens(n : Int) = { println("Kittens!"); if (kittens > 0) kittens(n
>> - 1) }
>> >
>> > I'm not sure what this used to translate to, but in 2.7.3 this will
>> > stack overflow given enough kittens whileas, in trunk it won't.
>> >
>>
>> Note that this works just as well with the Option version. It's a
>> compelling reason for either of them in preference to the existing
>> behaviour, not for the trunk behaviour vs. Option.
>>
>

DRMacIver
Joined: 2008-09-02,
User offline. Last seen 42 years 45 weeks ago.
Re: type of "if (x) Foo"

On Sat, Mar 14, 2009 at 9:53 PM, Jorge Ortiz wrote:
> It wouldn't work in the Option case without extra compiler magic. In:
>
>    def kittens(n : Int): Option[Unit] = { println("Kittens!"); if (kittens >
> 0) kittens(n - 1) }
>
> You'd get a type mismatch because the return type of kittens(n - 1) is
> Option[Unit], so the return type of if(kittens > 0) kittens(n - 1) would be
> Option[Option[Unit]], which wouldn't conform to kitten's type signature.

Actually it doesn't work in either case, because you need to specify a
return type for recursive methods. But given a return type which works
(e.g. Unit, Any, Option[Any]) it should still work in the Option
version.

David Pollak
Joined: 2008-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: type of "if (x) Foo"

Coolio

On Mar 14, 2009 10:09 PM, "Alex Boisvert" <boisvert [at] intalio [dot] com> wrote:

Just an idea, maybe this form:

if (foo) yield bar

could produce Option[Bar].  With no else clause allowed.

alex

On 3/14/09, Jorge Ortiz <jorge [dot] ortiz [at] gmail [dot] com> wrote: > It wouldn't work in the Option case withou...

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: type of "if (x) Foo"
It "works" in the sense of "compiles", but it doesn't "work" because it still blows up your stack. With the Option semantics for if, when the return type is Any or Option[Any], the returned value would be something like Some(Some(Some(Some(None)))), or something similar, depending on how deep the recursion went. Without additional compiler magic, it would still blow up your stack and (granted, much less likely) your heap.

I don't know how return values are coerced to Unit, so using that may or may not work.

--j

On Sat, Mar 14, 2009 at 3:16 PM, David MacIver <david [dot] maciver [at] gmail [dot] com> wrote:
On Sat, Mar 14, 2009 at 9:53 PM, Jorge Ortiz <jorge [dot] ortiz [at] gmail [dot] com> wrote:
> It wouldn't work in the Option case without extra compiler magic. In:
>
>    def kittens(n : Int): Option[Unit] = { println("Kittens!"); if (kittens >
> 0) kittens(n - 1) }
>
> You'd get a type mismatch because the return type of kittens(n - 1) is
> Option[Unit], so the return type of if(kittens > 0) kittens(n - 1) would be
> Option[Option[Unit]], which wouldn't conform to kitten's type signature.

Actually it doesn't work in either case, because you need to specify a
return type for recursive methods. But given a return type which works
(e.g. Unit, Any, Option[Any]) it should still work in the Option
version.

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: type of "if (x) Foo"
if-comprehensions? ;)

I like the suggestion.

--j

On Sat, Mar 14, 2009 at 3:09 PM, Alex Boisvert <boisvert [at] intalio [dot] com> wrote:
Just an idea, maybe this form:

if (foo) yield bar

could produce Option[Bar].  With no else clause allowed.

alex

On 3/14/09, Jorge Ortiz <jorge [dot] ortiz [at] gmail [dot] com> wrote:
> It wouldn't work in the Option case without extra compiler magic. In:
>
>    def kittens(n : Int): Option[Unit] = { println("Kittens!"); if (kittens >
> 0) kittens(n - 1) }
>
> You'd get a type mismatch because the return type of kittens(n - 1) is
> Option[Unit], so the return type of if(kittens > 0) kittens(n - 1) would be
> Option[Option[Unit]], which wouldn't conform to kitten's type signature.
>
> --j
>
> On Sat, Mar 14, 2009 at 4:34 AM, David MacIver
> <david [dot] maciver [at] gmail [dot] com>wrote:
>
>> On Sat, Mar 14, 2009 at 11:34 AM, David MacIver <david [dot] maciver [at] gmail [dot] com>
>> wrote:
>> > On Sat, Mar 14, 2009 at 7:26 AM, David Pollak
>> > <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:
>> >>
>> >>
>> >> On Sat, Mar 14, 2009 at 3:51 AM, Paul Phillips <paulp [at] improving [dot] org>
>> wrote:
>> >>>
>> >>> On Sat, Mar 14, 2009 at 06:04:31AM +0300, Stepan Koltsov wrote:
>> >>> > I haven't read the start of the discussion :) Changing type of if to
>> >>> > Any is bad. Don't you know what is motivation behind that change?
>> >>>
>> >>> I don't know.  I should clarify, it actually expands to
>> >>>
>> >>>  if (cond) x else ()
>> >>
>> >> I'm guessing that this is to make:
>> >> <foo>
>> >> {
>> >>   if (baz) "bar"
>> >> }
>> >> </foo>
>> >> Behave as some people expect it to.  I'm not keen on either change.
>>  From a
>> >> "newbie mistake with XML" standpoint, the change on trunk makes more
>> sense.
>> >>  From a purish FP standpoint, a partially applied if is kinda amusing.
>>  I
>> >> would hope that one would optimize it such that it would only create
>> >> the
>> >> Some() in the case of assignment or generation of a return value.
>> >
>> > There's actually a very compelling reason for the trunk version: Tail
>> > call optimisation doesn't work with the version as it stands in 2.7.3
>> >
>> > def kittens(n : Int) = { println("Kittens!"); if (kittens > 0) kittens(n
>> - 1) }
>> >
>> > I'm not sure what this used to translate to, but in 2.7.3 this will
>> > stack overflow given enough kittens whileas, in trunk it won't.
>> >
>>
>> Note that this works just as well with the Option version. It's a
>> compelling reason for either of them in preference to the existing
>> behaviour, not for the trunk behaviour vs. Option.
>>
>

Alex Cruise
Joined: 2008-12-17,
User offline. Last seen 2 years 26 weeks ago.
Re: type of "if (x) Foo"

Dave Griffith wrote:
> There are a lot of cases where people write method that are conceptually
> "statements" (i.e, called for side effects), but which nonetheless are
> syntactically "expressions" (i.e value-returning). Many of the
> state-modifying methods in the Java collections library, for instance,
> return an indicator of the past contents of a collection. This is arguably
> bad style, but certain pretty fundamental concurrency operations are
> difficult to model any other way.
>
Yes, but if is a built-in with a lot of baggage, not just any
expression. FWIW I would also like a warning/annotation for ignoring the
return value of a pure function, but obviously we're missing a few
layers of infrastructure to make that possible. :)

-0xe1a

Dave Griffith
Joined: 2009-01-14,
User offline. Last seen 42 years 45 weeks ago.
Re: type of "if (x) Foo"

Not as many as you might think. The IntelliJ IDEA inspections package for
Scala I'm working (intermittently) on includes warnings for ignored return
values. For a start, only some common failure cases will be caught (String
operations, operations on immutable collections), but there will probably be
a way of annotating your methods (or classes) as immutable so that the
inspection can catch ignored return values on them.

Arrgh wrote:
>
>
> Yes, but if is a built-in with a lot of baggage, not just any
> expression. FWIW I would also like a warning/annotation for ignoring the
> return value of a pure function, but obviously we're missing a few
> layers of infrastructure to make that possible. :)
>
>

jherber
Joined: 2009-02-08,
User offline. Last seen 42 years 45 weeks ago.
Re: type of "if (x) Foo"

Greetings all, returning after a 4 month Scala hiatus.

Alex Boisvert-3 wrote:
>
> if (foo) yield bar
>
> could produce Option[Bar]. With no else clause allowed.
>

Nice direction, but I'd take it a slightly different direction:

"if (foo) Some(bar)" is the only valid form of one legged if that should be
allowed. It resolves to:
"if (foo) Some(bar) else None", with type Option[Bar]
Rational: Reward use of Option monad for intended use. Expansion is
obvious to those who understand what Option monad means. Type is obvious
...

"if (foo) bar" form should result in a compile-time syntax error with a
clear warning targeted at Java users.
Rational: Scala should bend towards Java where it does not compromise the
integrity of the language. In this case, it should not bend, since
statements <> expressions. The resultant error message will quickly provide
user feedback for those coming from statement centric world. The current
behavior is a design flaw because: (1) the implied "Unit" default is
non-obvious, non-warning source of errors for new users and those skimming
code, (2) special cases increases complexity of language.

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