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

main methods

13 replies
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.

I think https://lampsvn.epfl.ch/trac/scala/ticket/363 threw out an awful lot of baby from a bath that was much
larger than necessary anyway. The patch was reverted because adding static forwarders for every
non-name-conflicting method to the companion class caused some not-yet-explained issues, and indeed that's still
true. But the essence of the bug and what I imagine to capture 99% of the use cases is that an object with a
main method cannot be used as an entry point if it has any companion class at all.

In other words, there's only one method which needs forwarding. I implemented it that way (looking for a method
called "main" in the companion object and adding a forwarder if it exists) and it works great with no visible
unhappiness from the compiler.

Does anyone object or see an issue?

(Parenthetically, the pathological example given in the ticket -- where there are methods named "main" in both
class and companion object -- still won't work.)

Alex Cruise
Joined: 2008-12-17,
User offline. Last seen 2 years 26 weeks ago.
Re: main methods

Paul Phillips wrote:
> ... the essence of the bug and what I imagine to capture 99% of the use cases is that an object with a main method cannot be used as an entry point if it has any companion class at all.
>
FWIW I reported the bug originally; I was trying to do the Scala analog
of the typical Java:

class Foo {
private Foo() { }
private void doStuff(String[] args) { }

public static void main(String[] args) {
Foo me = new Foo();
me.doStuff(args);
}
}

Now I don't think I'd try it, just because it feels like bad form, not
because I know it won't work. :)
> (Parenthetically, the pathological example given in the ticket -- where there are methods named "main" in both class and companion object -- still won't work.)
>
I would never expect to be able to use *both* main methods. I was just
trying to figure out what kind of main method might work.

-0xe1a

odersky
Joined: 2008-07-29,
User offline. Last seen 45 weeks 6 days ago.
Re: main methods

I'd be happy to see that patch. Maybe Iulian can also comment, he's
the one who worked on the forwarders.

Cheers

Iulian Dragos 2
Joined: 2009-02-10,
User offline. Last seen 42 years 45 weeks ago.
Re: main methods

A few weeks ago Miles offered to take over this bug. I have no idea
about his progress.

I'd rather have a fix for the original patch, but I won't oppose
having a first step that fixes 99% of the use cases.

Iulian

On Feb 19, 2009, at 7:36 PM, martin odersky wrote:

> I'd be happy to see that patch. Maybe Iulian can also comment, he's
> the one who worked on the forwarders.
>
> Cheers
>

milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: main methods

On Thu, Feb 19, 2009 at 8:39 PM, Iulian Dragos wrote:
> A few weeks ago Miles offered to take over this bug. I have no idea about
> his progress.
>
> I'd rather have a fix for the original patch, but I won't oppose having a
> first step that fixes 99% of the use cases.

Yes I did, but I've been far too busy with plugin stuff to make any
headway on it. I'd be absolutely delighted to see Paul pick it up.

Cheers,

Miles

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: main methods

On Thu, Feb 19, 2009 at 09:39:20PM +0100, Iulian Dragos wrote:
> I'd rather have a fix for the original patch, but I won't oppose having a
> first step that fixes 99% of the use cases.

Sounds like we're all in agreement that whatever percentages I make up are totally reliable. Great! It's now in
trunk.

James Iry
Joined: 2008-08-19,
User offline. Last seen 1 year 23 weeks ago.
Re: main methods
Besides that 99% of the use cases I think the other 47% of the use cases are to make such methods more easily accessible from Java.

On Thu, Feb 19, 2009 at 1:35 PM, Paul Phillips <paulp@improving.org> wrote:
On Thu, Feb 19, 2009 at 09:39:20PM +0100, Iulian Dragos wrote:
> I'd rather have a fix for the original patch, but I won't oppose having a
> first step that fixes 99% of the use cases.

Sounds like we're all in agreement that whatever percentages I make up are totally reliable.  Great! It's now in
trunk.

--
Paul Phillips      | Adultery is the application of democracy to love.
In Theory          |     -- H. L. Mencken
Empiricist         |
i'll ship a pulp   |----------* http://www.improving.org/paulp/ *----------

Iulian Dragos 2
Joined: 2009-02-10,
User offline. Last seen 42 years 45 weeks ago.
Re: main methods

It seems the original problem is still here. It's something related to
calling 'info' during bytecode generation (it triggers classfile
loading, and steps on newly generated code... beats me why that is a
problem, though). If that is solved, the original patch will work as
well. Here's a stack trace I get while building the compiler with the
quick compiler (probably the nightly will fail when building strap):

dragos@dragos-mbp scala $ bscalac -d build/quick/classes/compiler/ -
cp /usr/share/ant/lib/ant.jar:lib/msil.jar:lib/fjbg.jar:lib/jline.jar
`find src/compiler/ -iname *.scala`
error: error while loading Opcodes$opcodes$SuperCall, class file
'build/quick/classes/compiler/scala/tools/nsc/backend/icode/Opcodes
$opcodes$SuperCall.class' is broken
(class scala.tools.nsc.backend.icode.Opcodes$opcodes not found.)
error: error while loading CopyPropagation$CopyAnalysis$$anonfun
$interpret$2, class file 'build/quick/classes/compiler/scala/tools/nsc/
backend/icode/analysis/CopyPropagation$CopyAnalysis$$anonfun$interpret
$2.class' is broken
(class scala.tools.nsc.backend.icode.analysis.CopyPropagation
$copyLattice not found.)
error: error while loading Opcodes$opcodes$CALL_METHOD, class file
'build/quick/classes/compiler/scala/tools/nsc/backend/icode/Opcodes
$opcodes$CALL_METHOD.class' is broken
(class scala.tools.nsc.backend.icode.Opcodes$opcodes not found.)
Exception in thread "main" java.lang.AssertionError: assertion failed:
class Plugin
at scala.Predef$.assert(Predef.scala:92)
at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses
$.innerSymbol$1(ClassfileParser.scala:965)
at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses
$.classSymbol(ClassfileParser.scala:977)
at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses
$.innerSymbol$1(ClassfileParser.scala:962)
at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses
$.classSymbol(ClassfileParser.scala:977)
at
scala
.tools
.nsc
.symtab
.classfile.ClassfileParser.classNameToSymbol(ClassfileParser.scala:343)
at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type
$1(ClassfileParser.scala:598)
at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type
$1(ClassfileParser.scala:615)
at scala.tools.nsc.symtab.classfile.ClassfileParser.scala$tools$nsc
$symtab$classfile$ClassfileParser$$sigToType(ClassfileParser.scala:668)
at scala.tools.nsc.symtab.classfile.ClassfileParser
$ConstantPool.getType(ClassfileParser.scala:287)
at
scala
.tools
.nsc
.symtab.classfile.ClassfileParser.parseMethod(ClassfileParser.scala:482)
at scala.tools.nsc.symtab.classfile.ClassfileParser$$anonfun
$parseClass$2.apply(ClassfileParser.scala:409)
at scala.tools.nsc.symtab.classfile.ClassfileParser$$anonfun
$parseClass$2.apply(ClassfileParser.scala:409)
at scala.Range.foreach(Range.scala:44)
at
scala
.tools
.nsc.symtab.classfile.ClassfileParser.parseClass(ClassfileParser.scala:
409)
at
scala
.tools
.nsc.symtab.classfile.ClassfileParser.parse(ClassfileParser.scala:85)
at scala.tools.nsc.symtab.SymbolLoaders$ClassfileLoader$$anonfun
$doComplete$3.apply(SymbolLoaders.scala:306)
at scala.tools.nsc.symtab.SymbolLoaders$ClassfileLoader$$anonfun
$doComplete$3.apply(SymbolLoaders.scala:306)
at
scala
.tools.nsc.symtab.SymbolLoaders.completeClassfile(SymbolLoaders.scala:
292)
at scala.tools.nsc.symtab.SymbolLoaders
$ClassfileLoader.doComplete(SymbolLoaders.scala:305)
at scala.tools.nsc.symtab.SymbolLoaders
$SymbolLoader.complete(SymbolLoaders.scala:77)
at scala.tools.nsc.symtab.Symbols$Symbol.info(Symbols.scala:623)
at scala.tools.nsc.backend.jvm.GenJVM$BytecodeGenerator.mainSym
$1(GenJVM.scala:211)
at scala.tools.nsc.backend.jvm.GenJVM
$BytecodeGenerator.mainForwarderNeeded$1(GenJVM.scala:216)
at scala.tools.nsc.backend.jvm.GenJVM
$BytecodeGenerator.genClass(GenJVM.scala:220)
at scala.tools.nsc.backend.jvm.GenJVM$JvmPhase$$anonfun$run
$2.apply(GenJVM.scala:55)
at scala.tools.nsc.backend.jvm.GenJVM$JvmPhase$$anonfun$run
$2.apply(GenJVM.scala:55)
at scala.Iterator$class.foreach(Iterator.scala:414)
at scala.collection.Map$$anon$6.foreach(Map.scala:123)
at scala.tools.nsc.backend.jvm.GenJVM$JvmPhase.run(GenJVM.scala:55)
at scala.tools.nsc.Global$Run.compileSources(Global.scala:689)
at scala.tools.nsc.Global$Run.compile(Global.scala:784)
at scala.tools.nsc.Main$.process(Main.scala:73)
at scala.tools.nsc.Main$.main(Main.scala:87)
at scala.tools.nsc.Main.main(Main.scala)

On Feb 19, 2009, at 10:35 PM, Paul Phillips wrote:

> On Thu, Feb 19, 2009 at 09:39:20PM +0100, Iulian Dragos wrote:
>> I'd rather have a fix for the original patch, but I won't oppose
>> having a
>> first step that fixes 99% of the use cases.
>
> Sounds like we're all in agreement that whatever percentages I make
> up are totally reliable. Great! It's now in
> trunk.
>

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: main methods

On Fri, Feb 20, 2009 at 12:01:19AM +0100, Iulian Dragos wrote:
> It seems the original problem is still here. It's something related to
> calling 'info' during bytecode generation (it triggers classfile loading,
> and steps on newly generated code... beats me why that is a problem,
> though). If that is solved, the original patch will work as well. Here's a
> stack trace I get while building the compiler with the quick compiler
> (probably the nightly will fail when building strap):

Are you sure that's not just another binary mismatch? I did do a full rebuild/test nightly style before
comitting, everything passed smoothly, but even so it's true that a failure wouldn't be a huge shocker.

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: main methods

On Fri, Feb 20, 2009 at 12:01:19AM +0100, Iulian Dragos wrote:
> It seems the original problem is still here. It's something related to
> calling 'info' during bytecode generation (it triggers classfile loading,
> and steps on newly generated code... beats me why that is a problem,
> though). If that is solved, the original patch will work as well.

Okay, as far as I can tell I have a patch which fixes #1735. All tests pass and many classes have shiny new
forwarders. However, since I am guessing there is some reason it was done this way, perhaps Iulian or someone
could comment on the patch (which is longer than this, but the rest is immaterial.)

- for (m <- atPhase(currentRun.picklerPhase)(module.tpe.nonPrivateMembers); if shouldForward(m))
+ for (m <- module.info.nonPrivateMembers; if shouldForward(m))

Iulian Dragos 2
Joined: 2009-02-10,
User offline. Last seen 42 years 45 weeks ago.
Re: main methods

Quoting Paul Phillips :

> Okay, as far as I can tell I have a patch which fixes #1735. All
> tests pass and many classes have shiny new
> forwarders. However, since I am guessing there is some reason it
> was done this way, perhaps Iulian or someone
> could comment on the patch (which is longer than this, but the rest
> is immaterial.)
>
> - for (m <-
> atPhase(currentRun.picklerPhase)(module.tpe.nonPrivateMembers); if
> shouldForward(m))
> + for (m <- module.info.nonPrivateMembers; if shouldForward(m))

I think we look at types at pickler phase in order to only see members
that were written explicitly by the programmer.

iulian

>
> --
> Paul Phillips | Every normal man must be tempted at times
> Future Perfect | to spit on his hands, hoist the black flag,
> Empiricist | and begin to slit throats.
> pal, i pill push | -- H. L. Mencken
>

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: main methods

On Mon, Feb 23, 2009 at 01:35:53PM +0100, iulian.dragos@epfl.ch wrote:
> I think we look at types at pickler phase in order to only see members
> that were written explicitly by the programmer.

Ah, to avoid generating forwarders for synthetics? I thought it might be something like that. In fact I tried poking my head
into the pickler phase just long enough to get the method names and then drawing all the other information from the current
phase, but that caused the same troubles.

If we should be very surprised that trying to perform this operation in an earlier phase causes these errors, then that is
probably the bug of interest now. If we agree that the current implementation works and that avoiding what I hope is just a few
extra forwarders is essentially an optimization, then I intend to shelve this until some other bug forces me to examine the
atPhase mechanics more closely.

Iulian Dragos 2
Joined: 2009-02-10,
User offline. Last seen 42 years 45 weeks ago.
Re: main methods

Quoting Paul Phillips :

> On Mon, Feb 23, 2009 at 01:35:53PM +0100, iulian.dragos@epfl.ch wrote:
>> I think we look at types at pickler phase in order to only see members
>> that were written explicitly by the programmer.
>
> Ah, to avoid generating forwarders for synthetics? I thought it
> might be something like that. In fact I tried poking my head
> into the pickler phase just long enough to get the method names and
> then drawing all the other information from the current
> phase, but that caused the same troubles.
>
> If we should be very surprised that trying to perform this operation
> in an earlier phase causes these errors, then that is
> probably the bug of interest now. If we agree that the current
> implementation works and that avoiding what I hope is just a few
> extra forwarders is essentially an optimization, then I intend to
> shelve this until some other bug forces me to examine the
> atPhase mechanics more closely.

Unfortunately I am forced to choose between running Windows and having
an internet connection or hacking Scala. Could you reproduce the
errors I sent you in an earlier message, and this change is a fix for
those? (it's about recompiling a single file to the output directory).

Iulian

>
> --
> Paul Phillips | On two occasions, I have been asked, 'Mr.
> Babbage, if you
> Protagonist | put into the machine wrong figures, will the
> right answers
> Empiricist | come out?' I am not able to rightly apprehend
> the kind of
> pal, i pill push | confusion of ideas that could provoke such a question.
>

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: main methods

On Mon, Feb 23, 2009 at 02:35:17PM +0100, iulian.dragos@epfl.ch wrote:
> Unfortunately I am forced to choose between running Windows and having an
> internet connection or hacking Scala. Could you reproduce the errors I
> sent you in an earlier message, and this change is a fix for those? (it's
> about recompiling a single file to the output directory).

I can't swear I reproduced that exact error, but I did get a variety of errors which looked to have the same cause, all of which
went away when I removed the atPhase code. So in a word, yes.

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