[Not a sip] Deprecating language features for 2.10

1,724 views
Skip to first unread message

martin odersky

unread,
Mar 20, 2012, 6:21:09 PM3/20/12
to scala...@googlegroups.com
This is not yet a SIP, and I am not sure one will be needed. I wanted
to propose we deprecate two language features for 2.10, DelayedInit
and view bounds.

DelayedInit

DelayedInit was introduced in 2.9 to fix Application and generally to
be able to inject some bindings into the scope of a block. The idea
was that the block would be really a template of a class or object,
that the binding would be introduced via inheritance, and that we
could get out of the straightjacket of running the template code in a
constructor through DelayedInit. I believe we will have with macros a
better way to do the binding injection, which has the advantage that
we can use real blocks of code and not use templates. Here's an
example of what I mean:

One use case of DelayedInit was that we should be able to write:

new Transaction { << code >> }.start

where the idea of defining <<code>> in the Transaction template was
that, that way, <<code>> could automatically inherit an (implicit)
transaction context. But we really want to run <<code>> outside of the
constructor, hence Transaction would inherit from DelayedInit. I think
with macros we can achieve the same effect in a much simpler way:

atomic { << code >> }

The transaction context would be injected by AST manipulation.

That leaves us with the problem how to simulate App going forward. I
hope that in the future that can also be done with a (type) macro. But
details would need to be worked out. If this would not work out I'd
prefer to special case App in the compiler rather than support the
DelayedInit feature. An alternative, which I believe we should have
done from the start, but which might introduce too much change now,
would be to write an application as follows:

object Test extends App {
def main() {
...
}
}

That means, the only thing App would buy us would be the ability to
define a zero-parameter main method. That could be called from the
standard main that has an Array[String] parameter, and no delayed init
tricks would be needed (My fingers always stumble when I write the
(args: Array[String]) bit.). In retrospect, I believe this would have
been the best scheme, but I am not sure we can do it now. Maybe that's
too much code to change for something too trivial.

But in summary, I believe we should get rid of DelayedInit if macros
are accepted into the language.


View Bounds

It seems perverse that we would have syntactic sugar for implicit
conversions that we propose to put under a feature flag because they
are so easily misused. So I propose to deprecate view bounds.

Your thoughts?

Cheers

- Martin

Eugene Burmako

unread,
Mar 20, 2012, 6:29:25 PM3/20/12
to scala...@googlegroups.com

Speaking of syntactic sugar. Will we need a flag to declare an implicit class?

martin odersky

unread,
Mar 20, 2012, 6:34:27 PM3/20/12
to scala...@googlegroups.com
On Tue, Mar 20, 2012 at 11:29 PM, Eugene Burmako <eugene....@epfl.ch> wrote:
> Speaking of syntactic sugar. Will we need a flag to declare an implicit
> class?

I don't think we should need a flag for that (provided SIP 13 is accepted)

Cheers

- Martin

--
Martin Odersky
Prof., EPFL and Chairman, Typesafe
PSED, 1015 Lausanne, Switzerland
Tel. EPFL: +41 21 693 6863
Tel. Typesafe: +41 21 691 4967

Simon Ochsenreither

unread,
Mar 20, 2012, 6:54:26 PM3/20/12
to scala...@googlegroups.com
Hi,

I always had the feeling that DelayedInit was a bit of premature abstraction. I can't think of any library which ever used it.

Maybe DelayedInit could be deprecated, but not shown for App and removed from documentation so thet the inner working of App is some implementation detail which can be switched out when macros are availabe.

I don't like the idea of having   object Test extends App { def main() { ... }}.

I would prefer even the status quo before DelayedInit (big warning signs on Application to not use it in production) to such a solution.

No opinion on view bounds.

Thanks and bye!


Simon

Simon Ochsenreither

unread,
Mar 20, 2012, 6:56:27 PM3/20/12
to scala...@googlegroups.com
I really wonder what happens when we basically get stuff like @inline implicit class Foo(...) extends AnyVal.

Andreas Flierl

unread,
Mar 20, 2012, 7:06:04 PM3/20/12
to scala...@googlegroups.com
Hi,

martin odersky wrote :

> But in summary, I believe we should get rid of DelayedInit if macros
> are accepted into the language.

I agree.

> View Bounds
>
> It seems perverse that we would have syntactic sugar for implicit
> conversions that we propose to put under a feature flag because they
> are so easily misused. So I propose to deprecate view bounds.
>
> Your thoughts?

Are they problematic in any way? Deprecating them seems drastic. If we must have feature flags, why not hide them behind the same flag as implicits?

What about context bounds? Are implicit values perceived as similarly "easily misused" as implicit conversions? I guess not, but just asking anyway. :)

Kind regards
Andreas

martin odersky

unread,
Mar 20, 2012, 7:10:48 PM3/20/12
to scala...@googlegroups.com
On Wed, Mar 21, 2012 at 12:06 AM, Andreas Flierl <and...@flierl.eu> wrote:
> Hi,
>
> martin odersky wrote :
>
>> But in summary, I believe we should get rid of DelayedInit if macros
>> are accepted into the language.
>
> I agree.
>
>> View Bounds
>>
>> It seems perverse that we would have syntactic sugar for implicit
>> conversions that we propose to put under a feature flag because they
>> are so easily misused. So I propose to deprecate view bounds.
>>
>> Your thoughts?
>
> Are they problematic in any way? Deprecating them seems drastic. If we must have feature flags, why not hide them behind the same flag as implicits?

Getting rid of them would simplify the language, which is something
I'm very keen to do.

> What about context bounds? Are implicit values perceived as similarly "easily misused" as implicit conversions? I guess not, but just asking anyway. :)
>

No context bounds are essentially the replacement of view bounds. It's
what we should have done from the start, but we did not know better
back then. So certainly no wish to deprecate them

Cheers

- Martin


> Kind regards
> Andreas

Daniel Sobral

unread,
Mar 20, 2012, 7:15:18 PM3/20/12
to scala...@googlegroups.com
On Tue, Mar 20, 2012 at 19:21, martin odersky <martin....@epfl.ch> wrote:
> This is not yet a SIP, and I am not sure one will be needed. I wanted
> to propose we deprecate two language features for 2.10, DelayedInit
> and view bounds.
>
> DelayedInit

I think deprecating it before type macros come in is too soon. That is
balanced by the fact that, if we are going to deprecate it, better do
it now. Perhaps even on 2.9.2 -- as long as people don't have to see
deprecation messages for using App.

> View Bounds
>
> It seems perverse that we would have syntactic sugar for implicit
> conversions that we propose to put under a feature flag because they
> are so easily misused. So I propose to deprecate view bounds.

Yeah, view bounds are dangerous, "T <% Ordered[T]" is still the way to
go about Ordered, which is much more convenient than Ordering. I
wouldn't do it before the ceremony of type classes gets decreased.

--
Daniel C. Sobral

I travel to the future all the time.

Eric Torreborre

unread,
Mar 20, 2012, 7:18:20 PM3/20/12
to scala...@googlegroups.com
Hi Martin,

Again, from a specs2 perspective I might not be happy with both changes.

DelayedInit actually saved the day for me when you introduced it because it allowed the creation of user defined "contexts" with "before" methods:

  // example of specification code
  "This is an example" in new UserContext {
     userName must have size(5)
  }

  // by extending Before and providing the 'before' method an action will be executed before each
  // example using the UserContext
  trait UserContext extends Before {
    def before = prepareDatabase
    def userName = Database.getUser.name
  }

  // FROM SPECS2
  /**
   * This trait adds the possibility to execute the before behavior before the body of the context.
   *
   * Since the delayedInit method doesn't return a Result, this only works with mutable 
   * specifications where results are thrown as exceptions
   */
  trait Before extends org.specs2.specification.Before with DelayedInit {
    override def delayedInit(x: => Unit): Unit = { before; x }
  }

I'm not sure how that scheme would work with macros. I want to be able to keep the "new UserContext" part because it allows the definition of "fresh" variables to be used for each example. But I have no experience yet with macros.

The other thing, view bounds, is also pretty wildly used in specs2 (155 usages). For example, there is an implicit used to build "Examples" from strings in a "Specification":

  implicit def inExample(s: String): InExample = new InExample(s)
  class InExample(s: String) {
    def in[T <% Result](r: =>T): Example = exampleFactory.newExample(s, r)
  }

This method accepts anything that is convertible to a Result: a Boolean, a "Standard" result, a "MatchResult", a Scalacheck Property,... What do you propose to use in that case? A type bound and a typeclass?

Also I don't know why view bounds have been abused so if someone could enlighten me, that'd be nice.

In other words I volunteer for the testing of the migration strategy if any of those 2 features should be deprecated!

Eric.

√iktor Ҡlang

unread,
Mar 20, 2012, 7:19:35 PM3/20/12
to scala...@googlegroups.com
You already know I'm all for that ;-)

Can we also deprecate JavaConversions?
 

Your thoughts?

Cheers

 - Martin



--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Andreas Flierl

unread,
Mar 20, 2012, 7:19:51 PM3/20/12
to scala...@googlegroups.com

martin odersky wrote :

> Getting rid of them would simplify the language, which is something
> I'm very keen to do.
>
>> What about context bounds? Are implicit values perceived as similarly "easily misused" as implicit conversions? I guess not, but just asking anyway. :)
>>
> No context bounds are essentially the replacement of view bounds. It's
> what we should have done from the start, but we did not know better
> back then. So certainly no wish to deprecate them

Right. That sounds like a good plan then, but the cost of migration might be pretty high.

martin odersky

unread,
Mar 20, 2012, 7:24:03 PM3/20/12
to scala...@googlegroups.com
2012/3/21 √iktor Ҡlang <viktor...@gmail.com>:
What exactly is wrong with JavaConversions? Something must be, but I
have not yet understood what exactly.

Cheers

- Martin


>>
>>
>> Your thoughts?
>>
>> Cheers
>>
>>  - Martin
>
>
>
>
> --
> Viktor Klang
>
> Akka Tech Lead
> Typesafe - The software stack for applications that scale
>
> Twitter: @viktorklang
>

--

√iktor Ҡlang

unread,
Mar 20, 2012, 7:38:57 PM3/20/12
to scala...@googlegroups.com

I think Jorge can come up with some colorful examples where they blow up.

Cheers,
 

Cheers

- Martin


>>
>>
>> Your thoughts?
>>
>> Cheers
>>
>>  - Martin
>
>
>
>
> --
> Viktor Klang
>
> Akka Tech Lead
> Typesafe - The software stack for applications that scale
>
> Twitter: @viktorklang
>



--
Martin Odersky
Prof., EPFL and Chairman, Typesafe
PSED, 1015 Lausanne, Switzerland
Tel. EPFL: +41 21 693 6863
Tel. Typesafe: +41 21 691 4967

martin odersky

unread,
Mar 20, 2012, 7:44:13 PM3/20/12
to scala...@googlegroups.com

I actually found nothing in that thread that could be constructed as
an argument against JavaConversions.

- Martin

√iktor Ҡlang

unread,
Mar 20, 2012, 7:55:43 PM3/20/12
to scala...@googlegroups.com

Josh Suereth

unread,
Mar 20, 2012, 9:19:40 PM3/20/12
to scala...@googlegroups.com
Let's not confuse JavaConversions with JavaConverters.  JavaConverters == rockin.  JavaConversions == DANGER WILL ROBINSON!

2012/3/20 √iktor Ҡlang <viktor...@gmail.com>

Josh Suereth

unread,
Mar 20, 2012, 9:26:30 PM3/20/12
to scala...@googlegroups.com
App is the primary reason I see for keeping DelayedInit.  So, I'd be willing to trash it, *if* we can make a DelayedInit macro class.  I think people would see the benefit there, removing a language feature without losing any power.   Other than that, you're right in wanting to evict it I think.   Macros *should* be able to fulfill its role.


As for view bounds, I'm *all for* deprecating and warning on them, and eventual removal.   I don't mind fixing my code.   I think people are right in desiring less ceremony for type classes, and I hope we could follow on with ideas for that too, but honestly at this point right now I, I avoid view bounds like the plague, so it wouldn't affect me much.

If we do remove language features, we should make sure to add warnings for them in 2.10, and wait until 2.11 or later to actually remove.  Not that we would have done so without warnings and deprecation period, but just wanted to iterate for everyone that they would be there for any deprecation/removal that happens.

- Josh

martin odersky

unread,
Mar 21, 2012, 4:31:39 AM3/21/12
to scala...@googlegroups.com
It's actually very easy to get rid of view bounds. Here's an example:
A method with a view bound:

def foo[T <% Ordered[T]](x: T, y: T) = x < y

To get rid of the view bound, define a type alias

type OrderedView[T] = T => Ordered[T]

and rewrite foo to:

def foo[T: OrderedView](x: T, y: T) = x < y

The expanded result is exactly the same and it actually looks nicer!

Cheers

- Martin

--

martin odersky

unread,
Mar 21, 2012, 4:36:14 AM3/21/12
to scala...@googlegroups.com
On Wed, Mar 21, 2012 at 2:26 AM, Josh Suereth <joshua....@gmail.com> wrote:
> App is the primary reason I see for keeping DelayedInit.  So, I'd be willing
> to trash it, *if* we can make a DelayedInit macro class.  I think people
> would see the benefit there, removing a language feature without losing any
> power.   Other than that, you're right in wanting to evict it I think.
> Macros *should* be able to fulfill its role.
>
I don't think we will be able to make a macro that does exactly the
same things as DelayedInit in all circumstances. The problem is that
DelayedInit does fairly low-level stuff late in the compilation stage.
For instance, it expects that all vals have already been converted to
vars with explicit initializers. I think it will be very hard to
duplicate that in a macro that expands at typechecking time. But we
can simulate the essential motivation of DelayedInit, which was to
inject bindings into a scope automatically.

And I also think we can get something that works like App in all
normal circumstances, and that gives a compile-time error where this
fails.

Cheers

- Martin

martin odersky

unread,
Mar 21, 2012, 4:45:25 AM3/21/12
to scala...@googlegroups.com
Hi Eric,


> DelayedInit actually saved the day for me when you introduced it because it
> allowed the creation of user defined "contexts" with "before" methods:
>
>   // example of specification code
>   "This is an example" in new UserContext {
>      userName must have size(5)
>   }
>
>   // by extending Before and providing the 'before' method an action will be
> executed before each
>   // example using the UserContext
>   trait UserContext extends Before {
>     def before = prepareDatabase
>     def userName = Database.getUser.name
>   }
>
>   // FROM SPECS2
>   /**
>    * This trait adds the possibility to execute the before behavior before
> the body of the context.
>    *
>    * Since the delayedInit method doesn't return a Result, this only works
> with mutable
>    * specifications where results are thrown as exceptions
>    */
>   trait Before extends org.specs2.specification.Before with DelayedInit {
>     override def delayedInit(x: => Unit): Unit = { before; x }
>   }
>

Interesting use case! To do exactly the same we'd need type macros,
which do not yet exist. It seems you could do it with the current
macro scheme by converting the specification language to something
like that:

  "This is an example" in make[UserContext] {
     userName must have size(5)
  }

make could be a macro that creates the following expression:

new UserContext {
before
userName must have size(5)
  }

Cheers

- Martin

martin odersky

unread,
Mar 21, 2012, 8:53:06 AM3/21/12
to scala...@googlegroups.com

OK I see now. That because Java's collection libraries have chosen to
make get less type-safe than Scala's, with get taking an Object
parameter no matter what the key type of the map is. By importing from
JavaConversions you subscribe to the Java model of things even for
Scala collections.

It's annoying, but I don't think it's a killer if documented clearly.
I believe for people who work with Java collections instead of Scala
ones JavaConversions is still very useful.

One possible improvement would be to split JavaConversions into two
objects: JavaAsScala and ScalaAsJava. That would be more targeted
because then code that just wanted to use Java collections would not
pay the penalty of having Scala collections be converted by accident
to Java collections. If we do that we could deprecate JavaConversions
subsequently.

Cheers

- Martin

Paul Phillips

unread,
Mar 21, 2012, 9:21:07 AM3/21/12
to scala...@googlegroups.com
That's a good idea. I have to move everything around in there anyway;
I could create two traits holding implicits and three objects for
importing from (that being JavaAsScala, ScalaAsJava, and a recreation
of JavaConversions which inherits both traits.)

martin odersky

unread,
Mar 21, 2012, 9:27:40 AM3/21/12
to scala...@googlegroups.com
On Wed, Mar 21, 2012 at 2:21 PM, Paul Phillips <pa...@improving.org> wrote:
> That's a good idea.  I have to move everything around in there anyway;
> I could create two traits holding implicits and three objects for
> importing from (that being JavaAsScala, ScalaAsJava, and a recreation
> of JavaConversions which inherits both traits.)
>

Yes, I think that would be the right thing to do.

Cheers

- Martin

Paul Phillips

unread,
Mar 21, 2012, 10:41:00 AM3/21/12
to scala...@googlegroups.com

martin odersky

unread,
Mar 21, 2012, 10:42:33 AM3/21/12
to scala...@googlegroups.com

Cool! -- Martin

√iktor Ҡlang

unread,
Mar 21, 2012, 10:44:25 AM3/21/12
to scala...@googlegroups.com
Thanks Paul!

2012/3/21 martin odersky <martin....@epfl.ch>

Stefan Zeiger

unread,
Mar 21, 2012, 11:29:34 AM3/21/12
to scala...@googlegroups.com
On 2012-03-20 23:21, martin odersky wrote:
> One use case of DelayedInit was that we should be able to write:
>
> new Transaction {<< code>> }.start
>
> where the idea of defining<<code>> in the Transaction template was
> that, that way,<<code>> could automatically inherit an (implicit)
> transaction context. But we really want to run<<code>> outside of the
> constructor, hence Transaction would inherit from DelayedInit. I think
> with macros we can achieve the same effect in a much simpler way:
>
> atomic {<< code>> }
>
> The transaction context would be injected by AST manipulation.

How would you do that without untyped macros? Under the current
proposal, the macro argument has to type-check before the macro gets a
chance to modify it so it couldn't use any implicit value provided by
the macro (unless you provide a dummy value in an outer scope, but that
defeats the purpose of using DelayedInit or macros).

> That leaves us with the problem how to simulate App going forward.

I quite like the current App. But for a solution that would simplify the
language instead of complicate it, have you considered adding top-level
method definitions?

package com.example.myapp

@App
def Main(args: String...) =
println("Hello, World!)

Compilation wouldn't be straight-forward (perhaps you could turn such a
def into an object with an apply method?) but usage should be. A special
annotation (implemented as a compiler plugin or as an annotation macro)
could generate a static "main" forwarder and also hide some of the Java
ugliness, e.g. support varargs instead of Arrays and discard non-Unit
return values.

> View Bounds
>
> It seems perverse that we would have syntactic sugar for implicit
> conversions that we propose to put under a feature flag because they
> are so easily misused. So I propose to deprecate view bounds.

I see them as complimentary to context bounds. While context bounds are
often the right thing to use, they don't replace view bounds, and there
are still some situations where context bounds are not a good choice.
When we only had a hammer, all problems looked like nails, but now that
we also have a screwdriver, some problems still look like nails :)

-sz

martin odersky

unread,
Mar 21, 2012, 11:34:14 AM3/21/12
to scala...@googlegroups.com
On Wed, Mar 21, 2012 at 4:29 PM, Stefan Zeiger <sze...@novocode.com> wrote:
> On 2012-03-20 23:21, martin odersky wrote:
>>
>> One use case of DelayedInit was that we should be able to write:
>>
>>   new Transaction {<<  code>>  }.start
>>
>> where the idea of defining<<code>>  in the Transaction template was
>> that, that way,<<code>>  could automatically inherit an (implicit)
>> transaction context. But we really want to run<<code>>  outside of the
>> constructor, hence Transaction would inherit from DelayedInit. I think
>> with macros we can achieve the same effect in a much simpler way:
>>
>>   atomic {<<  code>>  }
>>
>> The transaction context would be injected by AST manipulation.
>
>
> How would you do that without untyped macros? Under the current proposal,
> the macro argument has to type-check before the macro gets a chance to
> modify it so it couldn't use any implicit value provided by the macro
> (unless you provide a dummy value in an outer scope, but that defeats the
> purpose of using DelayedInit or macros).
>

In some instances (like the one above) we can make it work with
default arguments. But in general we'll need macros with untyped
arguments for it, that's true.

- Martin

Stefan Zeiger

unread,
Mar 21, 2012, 12:30:09 PM3/21/12
to scala...@googlegroups.com

I missed your earlier reply to Josh about this. With the type alias
trick, that point is moot. You can indeed replace all view bounds by
context bounds (which are conceptually much easier to understand IMHO).

-sz

√iktor Ҡlang

unread,
Mar 21, 2012, 12:34:26 PM3/21/12
to scala...@googlegroups.com
On Wed, Mar 21, 2012 at 9:31 AM, martin odersky <martin....@epfl.ch> wrote:
It's actually very easy to get rid of view bounds. Here's an example:
A method with a view bound:

def foo[T <% Ordered[T]](x: T, y: T) = x < y

To get rid of the view bound, define a type alias

 type OrderedView[T] = T => Ordered[T]

and rewrite foo to:

def foo[T: OrderedView](x: T, y: T) = x < y

The expanded result is exactly the same and it actually looks nicer!

Very nice!

Rex Kerr

unread,
Mar 21, 2012, 1:05:28 PM3/21/12
to scala...@googlegroups.com
On Wed, Mar 21, 2012 at 4:31 AM, martin odersky <martin....@epfl.ch> wrote:
It's actually very easy to get rid of view bounds. Here's an example:
A method with a view bound:

def foo[T <% Ordered[T]](x: T, y: T) = x < y

To get rid of the view bound, define a type alias

 type OrderedView[T] = T => Ordered[T]

and rewrite foo to:

def foo[T: OrderedView](x: T, y: T) = x < y

The expanded result is exactly the same and it actually looks nicer!

That's great for a larger library.  For something small, it's twice as much work (as you have shown with your example above).  Also, it separates what you have to look at into two places: the method and the type declaration.  That slows down the rate at which you can comprehend unfamiliar code.

Until you use the same bound three or four times, you should just desugar:

    def foo[T](x: T, y:T)(implicit t2o: T => Ordered[T]) = x < y

This is less typing and keeps concerns more localized than your suggestion.

I think this is fine--I normally do it the long way anyway, since I like having explicit access to the implicit conversion.

But I don't think we should recommend a coding style for single-use cases that is less convenient than the explicit version.

And I don't think we should fool ourselves that the sugar does actually shorten things quite a bit.

(But the proposal is to flag all implicit conversions including context bounds which are implicit conversions, right?  So, sugar or no, the proposal is that you get a warning for all versions of foo.)

  --Rex

Andreas Flierl

unread,
Mar 21, 2012, 1:36:32 PM3/21/12
to scala...@googlegroups.com

Rex Kerr wrote:

> def foo[T](x: T, y:T)(implicit t2o: T => Ordered[T]) = x < y
>

Or inline:

def foo[A: ({type L[X] = X => Ordered[X]})#L](a: A, b: A) = a < b

That's equivalent, no?


Rex Kerr

unread,
Mar 21, 2012, 1:41:39 PM3/21/12
to scala...@googlegroups.com
Indeed, but the syntax is sufficiently clunky as to be less compact (and possibly less comprehensible to beginners, assuming that they hit implicits pretty early in the learning process) than the explicit implicit version.

So without cleaning up the syntax for in-line type definitions, I wouldn't recommend those either.  (But they're good to know about.)

  --Rex

Andreas Flierl

unread,
Mar 21, 2012, 1:51:42 PM3/21/12
to scala...@googlegroups.com
Hi,

Rex Kerr wrote:
> Indeed, but the syntax is sufficiently clunky as to be less compact (and possibly less comprehensible to beginners, assuming that they hit implicits pretty early in the learning process) than the explicit implicit version.
>
> So without cleaning up the syntax for in-line type definitions, I wouldn't recommend those either. (But they're good to know about.)

You're absolutely right. I still have some limited hope that inline type definitions get some syntax love at some point, though. :) At least for partial application of type constructors.

Kind regards
Andreas

Daniel Sobral

unread,
Mar 21, 2012, 2:37:04 PM3/21/12
to scala...@googlegroups.com

Deprecating without offering the alternative is meaningless, unless you intend to simply remove the feature. What are people supposed to do with deprecating warnings but replace the code? And what would they replace the code with?

Rex Kerr

unread,
Mar 21, 2012, 3:37:58 PM3/21/12
to scala...@googlegroups.com
+1.  This is exactly what I was just thinking and about to type up.

Eric Torreborre

unread,
Mar 21, 2012, 6:44:19 PM3/21/12
to scala...@googlegroups.com
If it's as easy as calling a macro, that might be ok. I haven't yet investigated the macro space for specs2 and I'm pretty sure I can find some interesting uses for them.

Now, I know that there are strong reasons to drop DelayedInit (cf Paul's last post) but I ask you please to make sure we have some proper replacement for it (as in my use case). I know that some users will have to rewrite some of their code and that'll be painful enough.

Thanks,

Eric.

Eric Torreborre

unread,
Mar 21, 2012, 6:47:53 PM3/21/12
to scala...@googlegroups.com
I'll give it a go on specs2 to see if everything compiles exactly the same and how tedious the change is (with 155 usages in my code base).

Eric.

Paul Phillips

unread,
Mar 21, 2012, 7:00:45 PM3/21/12
to scala...@googlegroups.com
How does one translate the view bounds in these methods?

scala> def f[T <% Int](x: T): Int = x
f: [T](x: T)(implicit evidence$1: T => Int)Int

scala> def f[K, V, T <% Map[K, V]](map: T, k: K) = map(k)
f: [K, V, T](map: T, k: K)(implicit evidence$1: T => Map[K,V])V

Stefan Zeiger

unread,
Mar 21, 2012, 7:20:50 PM3/21/12
to scala...@googlegroups.com
On 2012-03-22 0:00, Paul Phillips wrote:
> How does one translate the view bounds in these methods?
>
> scala> def f[T<% Int](x: T): Int = x
> f: [T](x: T)(implicit evidence$1: T => Int)Int
>
> scala> def f[K, V, T<% Map[K, V]](map: T, k: K) = map(k)
> f: [K, V, T](map: T, k: K)(implicit evidence$1: T => Map[K,V])V
scala> def f[T : ({ type L[X] = X => Int })#L](x: T): Int = x

f: [T](x: T)(implicit evidence$1: T => Int)Int

scala> def f[K, V, T : ({ type L[X] = T => Map[K, V] })#L](map: T, k: K)

= map(k)
f: [K, V, T](map: T, k: K)(implicit evidence$1: T =>

scala.collection.immutable.Map[K,V])V

A nicer syntax for type lambdas would help. The way these signatures
look, I'd write the desugared form directly.

-sz

Eric Torreborre

unread,
Mar 21, 2012, 10:06:15 PM3/21/12
to scala...@googlegroups.com
Ok, I'm sold on that one. 

The type alias works fine, and the resulting API, with a context bound instead of <% looks nicer. 

Eric.

Jorge Ortiz

unread,
Mar 21, 2012, 10:59:25 PM3/21/12
to scala...@googlegroups.com
On Wed, Mar 21, 2012 at 10:29 PM, Stefan Zeiger <sze...@novocode.com> wrote:
On 2012-03-20 23:21, martin odersky wrote:
That leaves us with the problem how to simulate App going forward.

I quite like the current App. But for a solution that would simplify the language instead of complicate it, have you considered adding top-level method definitions?

package com.example.myapp

@App
def Main(args: String...) =
 println("Hello, World!)

Compilation wouldn't be straight-forward (perhaps you could turn such a def into an object with an apply method?) but usage should be. A special annotation (implemented as a compiler plugin or as an annotation macro) could generate a static "main" forwarder and also hide some of the Java ugliness, e.g. support varargs instead of Arrays and discard non-Unit return values.

I like this proposal a lot better than DelayedInit or macros.

--j

nuttycom

unread,
Mar 21, 2012, 11:11:44 PM3/21/12
to scala...@googlegroups.com


On Wednesday, March 21, 2012 11:05:28 AM UTC-6, Rex Kerr wrote:
On Wed, Mar 21, 2012 at 4:31 AM, martin odersky wrote:
It's actually very easy to get rid of view bounds. Here's an example:
A method with a view bound:

def foo[T <% Ordered[T]](x: T, y: T) = x < y

To get rid of the view bound, define a type alias

 type OrderedView[T] = T => Ordered[T]

and rewrite foo to:

def foo[T: OrderedView](x: T, y: T) = x < y

The expanded result is exactly the same and it actually looks nicer!

That's great for a larger library.  For something small, it's twice as much work (as you have shown with your example above).  Also, it separates what you have to look at into two places: the method and the type declaration.  That slows down the rate at which you can comprehend unfamiliar code.

Until you use the same bound three or four times, you should just desugar:

    def foo[T](x: T, y:T)(implicit t2o: T => Ordered[T]) = x < y


Most of the time, I prefer to use Ordering[T] instead of Ordered[T] anyway, and this generalizes to essentially all uses of view bounds; a typeclass such as Ordering[T] is simply more flexible. So getting rid of view bounds makes a lot of sense.

As far as DelayedInit, it seems far more appropriate to use macros to satisfy these use cases if possible, rather than having yet another magical trait that the compiler knows about.

Kris 
 

Stefan Zeiger

unread,
Mar 22, 2012, 5:31:15 AM3/22/12
to scala...@googlegroups.com
On 2012-03-21 16:29, Stefan Zeiger wrote:
> I quite like the current App. But for a solution that would simplify
> the language instead of complicate it, have you considered adding
> top-level method definitions?
>
> package com.example.myapp
>
> @App
> def Main(args: String...) =
> println("Hello, World!)
>
> Compilation wouldn't be straight-forward (perhaps you could turn such
> a def into an object with an apply method?) but usage should be. A
> special annotation (implemented as a compiler plugin or as an
> annotation macro) could generate a static "main" forwarder and also
> hide some of the Java ugliness, e.g. support varargs instead of Arrays
> and discard non-Unit return values.

And without the need for top-level defs, how about this:

@App
class Main(args: String...) {
println("Hello, World!)
}

Again, the @App annotation makes the compiler (or annotation macro)
generate a static main method that instantiates the class. The class
needs to have a constructor which takes either an Array[String], a
Seq[String], or a String*.

-sz

martin odersky

unread,
Mar 22, 2012, 5:31:25 AM3/22/12
to scala...@googlegroups.com
The first one can be written more intelligibly like this:

scala> type IntView[T] = T => Int
defined type alias IntView

scala> def f[T: IntView](x: T): Int = x


f: [T](x: T)(implicit evidence$1: T => Int)Int

The second one cannot be abstracted into a context bound except with
the local type projection Stefan showed. We'd need partial type
parameter application for that. But it's a much rarer case, so I'd
recommend to just write the evidence parameter directly in that case.

Cheers

- Martin

Stefan Zeiger

unread,
Mar 22, 2012, 6:26:05 AM3/22/12
to scala...@googlegroups.com
On 2012-03-22 10:31, martin odersky wrote:
> The second one cannot be abstracted into a context bound except with
> the local type projection Stefan showed. We'd need partial type
> parameter application for that.

Well, you can still define a type alias for the projection, and it's
only slightly harder to use than the other ones:

scala> type MapView[K, V] = { type L[X] = X => Map[K, V] }
defined type alias MapView

scala> def f[K, V, T : MapView[K, V]#L](map: T, k: K) = map(k)


f: [K, V, T](map: T, k: K)(implicit evidence$1: T =>
scala.collection.immutable.Map[K,V])V

Partial application would still be nicer.

-sz

Miles Sabin

unread,
Mar 22, 2012, 8:01:48 AM3/22/12
to scala...@googlegroups.com

From my PoV partial application would more than pay the cost of
removing view bounds.

Cheers,


Miles

--
Miles Sabin
tel: +44 7813 944 528
gtalk: mi...@milessabin.com
skype: milessabin
g+: http://www.milessabin.com
http://twitter.com/milessabin
http://underscoreconsulting.com
http://www.chuusai.com

Simon Ochsenreither

unread,
Mar 22, 2012, 9:31:50 AM3/22/12
to scala...@googlegroups.com
What would be the benefit compared to “extends App”? We would need some special case either way.
Not saying everything is perfect, but if there are features introduced in 2.9.0 and backward incompatible ideas about removing it ahead of 2.9.2 with not really much benefit (from my perspective) it makes me certainly feel a bit worried.

martin odersky

unread,
Mar 22, 2012, 9:54:10 AM3/22/12
to scala...@googlegroups.com

I also think it would be a major problem if we had to replace the

extends App

syntax again. I'd very much prefer to keep it, to keep things stable.

- Martin

Daniel Sobral

unread,
Mar 22, 2012, 10:37:18 AM3/22/12
to scala...@googlegroups.com

Yes, please. Special case it for one or two releases before a general
replacement becomes available if you must, but don't change it again.


--
Daniel C. Sobral

I travel to the future all the time.

Eric Torreborre

unread,
May 1, 2012, 7:49:18 PM5/1/12
to scala...@googlegroups.com
I had a new use case this week for DelayedInit in specs2, so I really hope that you won't remove this functionality until there's an appropriate replacement.

Here's my use case (commit here: http://bit.ly/JBdE5b). I want the user to be able to mix-in a trait to his specification so that arguments coming from the command-line are accessible before any "specification code" is even executed:

      class MySpec extends Specification with CommandLineArguments {
          // arguments is an inherited method providing specs2 arguments passed on the command line
          if (arguments.include("tag")) "this is an ok example" >> ok
          else                                    skip("don't do anything")
      }
     
All in all this scheme is nice because:

 - additional functionality comes with just the addition of a new trait (no refactoring is necessary)

 - "Specification" is kept as a trait. An alternative would be to make it a class with a constructor having 'arguments' as a parameter. IMHO, this is not very nice. I think that sbt 0.7 had a similar issue with its API, where the Project class had to declare a constructor with one parameter (ProjectInfo, I think) even if the user was not really using it

 - the behaviour of specification can be modified without recompiling anything, just by passing different arguments on the command-line

martin odersky

unread,
May 2, 2012, 2:59:09 AM5/2/12
to scala...@googlegroups.com
Hi Eric,

Nice use case! I believe nothing will change for DelayedInit in 2.10, but on the other hand tickets relating to it will not have very high priority either. 

We will re-evaluate the situation once we have gained more experience with what macros can do. But it's good to have use cases like yours for that evaluation.

Cheers

 - Martin
Reply all
Reply to author
Forward
0 new messages