www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Entry (main) method inside a class?

reply Dejan Lekic <dejan.lekic gmail.com> writes:
Is there particular reason why we are not able to have entry (main) method
inside a class, like is possible in JAVA for an example?
Even though I am not a big JAVA fan, I must say I like that feature... :)

Kind regards

Dejan
Mar 16 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Dejan Lekic wrote:
 Is there particular reason why we are not able to have entry (main) method
inside a class, like is possible in JAVA for an example?
 Even though I am not a big JAVA fan, I must say I like that feature... :)

AFAIK the only reason Java has that "feature" is its complete inability to have functions *outside* of classes :). Though I could see uses for this, like to run unittests (similarly to what running Python modules "stand-alone" often does). D has gone another way there though, using explicit unittest {} blocks. Unfortunately, there is currently no way to run these separately (esp. right after compilation) that I know of.
Mar 16 2007
next sibling parent reply Benji Smith <dlanguage benjismith.net> writes:
Frits van Bommel wrote:
 Dejan Lekic wrote:
 Is there particular reason why we are not able to have entry (main) 
 method inside a class, like is possible in JAVA for an example?
 Even though I am not a big JAVA fan, I must say I like that feature... :)

AFAIK the only reason Java has that "feature" is its complete inability to have functions *outside* of classes :). Though I could see uses for this, like to run unittests (similarly to what running Python modules "stand-alone" often does). D has gone another way there though, using explicit unittest {} blocks. Unfortunately, there is currently no way to run these separately (esp. right after compilation) that I know of.

It can be convenient to package up a JAR file with multiple executable classes. Then you can run multiple different applications with the same binary just by passing a different app name on the commandline. It doesn't really apply to D, though. Without a runtime classloader, it doesn't make any sense to have a single EXE with multiple entry points. --benji
Mar 16 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Benji Smith wrote:
 Frits van Bommel wrote:
 Dejan Lekic wrote:
 Is there particular reason why we are not able to have entry (main) 
 method inside a class, like is possible in JAVA for an example?
 Even though I am not a big JAVA fan, I must say I like that 
 feature... :)



 It can be convenient to package up a JAR file with multiple executable 
 classes. Then you can run multiple different applications with the same 
 binary just by passing a different app name on the commandline.
 
 It doesn't really apply to D, though. Without a runtime classloader, it 
 doesn't make any sense to have a single EXE with multiple entry points.

I can think of several programs on my system that change their behavior depending on the value of argv[0]... Though perhaps not multiple entry points, that check + symlinks probably gets pretty close for compiled programs. Or you could use dynamic libraries (OS-native or DDL) together with small executables that load those libraries, saving you from having multiple versions of the shared code. Combining the techniques, I could even see a program that just loads argv[0] ~ ".so", looks up "void run()" in it and calls it. Then even the loader code is shared... However, the first technique doesn't work on Windows because it lacks symlinks (to files, at least). Though a few batch files that all run the same executable, each with a different --version=whatever (or some such) would look similar to the user.
Mar 16 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Frits van Bommel wrote

 However, the first technique doesn't work on Windows because it
 lacks symlinks (to files, at least).

XP supports hard links. -manfred
Mar 16 2007
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Manfred Nowak wrote:
 Frits van Bommel wrote
 
 However, the first technique doesn't work on Windows because it
 lacks symlinks (to files, at least).

XP supports hard links. -manfred

Yeah, but they suck. You need to download a third-party tool to use them, for starters. Secondly, almost nothing written for Windows even knows about them, not even *Explorer*, so it's impossible to tell if something is a link or not. And of course, they can't span drives. I'm fairly sure that one version of Windows could only hard-link folders, but not files. Not sure if that was 2k or XP. I once planned on using hard links to make migrating stuff between drives easier. Obviously I couldn't do that, but what really scared me was when I realised that deleting the link deleted the original as well; I just backed away slowly, avoiding eye contact. Vista has, I believe, *proper* symlinks... but then I'm moving to Linux before I touch Vista with a 50ft barge pole, so I don't care :) -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Mar 16 2007
prev sibling parent reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Frits van Bommel schrieb am 2007-03-16:
 Dejan Lekic wrote:
 Is there particular reason why we are not able to have entry (main) method
inside a class, like is possible in JAVA for an example?
 Even though I am not a big JAVA fan, I must say I like that feature... :)

AFAIK the only reason Java has that "feature" is its complete inability to have functions *outside* of classes :). Though I could see uses for this, like to run unittests (similarly to what running Python modules "stand-alone" often does). D has gone another way there though, using explicit unittest {} blocks. Unfortunately, there is currently no way to run these separately (esp. right after compilation) that I know of.

Flectioned's unittest walker does exactly that: dmd -unittest -g -c <your source> dmd flectioned.d unittest_walker.d -ofwhatever <your objects> ./whatever http://flectioned.kuehne.cn Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFF+9PRLK5blCcjpWoRAoiGAJ91UUkumd3LfoFb771S1Z/Y42ADowCfaqqT JN5WpxZdThF7LTl906mSs04= =R0ZY -----END PGP SIGNATURE-----
Mar 17 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Thomas Kuehne wrote:
 Frits van Bommel schrieb am 2007-03-16:
 Though I could see uses for this, like to run unittests (similarly to 
 what running Python modules "stand-alone" often does).
 D has gone another way there though, using explicit unittest {} blocks. 
 Unfortunately, there is currently no way to run these separately (esp. 
 right after compilation) that I know of.

Flectioned's unittest walker does exactly that: dmd -unittest -g -c <your source> dmd flectioned.d unittest_walker.d -ofwhatever <your objects> ./whatever http://flectioned.kuehne.cn

Interesting, I wasn't aware of that. Looking at the source though, is there any particular reason the code is in a static this() instead of in the empty void main() at the end? Shouldn't unit tests be performed after all static constructors have been completed, so that the modules being tested have been initialized? That, to me, indicates that the code should be in main(). Though with the recommended lines the code linked from .ctors probably links the ModuleInfo in the right order (from what I remember, it links each module at the head of the linked list, reversing the order), that doesn't look very robust. And why the empty main()? Is that to make sure that one gets linked instead of any main() provided in the other object files? And a static constructor that shuts down the gc and ends the program also just seems a bit fishy :), though in this case (given that the code is in a static this()) it seems to be what you want to do. But what exactly is the use case here? To just run the unit tests and avoid running main()? Wouldn't that be more easily accomplished by just letting the unit tests run "manually" and providing an empty main()? Of course, that wouldn't provide as nice an example of flectioned use :P .
Mar 17 2007
parent reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Frits van Bommel schrieb am 2007-03-17:
 Thomas Kuehne wrote:
 Frits van Bommel schrieb am 2007-03-16:
 Though I could see uses for this, like to run unittests (similarly to 
 what running Python modules "stand-alone" often does).
 D has gone another way there though, using explicit unittest {} blocks. 
 Unfortunately, there is currently no way to run these separately (esp. 
 right after compilation) that I know of.

Flectioned's unittest walker does exactly that: dmd -unittest -g -c <your source> dmd flectioned.d unittest_walker.d -ofwhatever <your objects> ./whatever http://flectioned.kuehne.cn

Interesting, I wasn't aware of that. Looking at the source though, is there any particular reason the code is in a static this() instead of in the empty void main() at the end?

Yes, "int main(char[][])" isn't executed until after the unittests are run.
 Shouldn't unit tests be performed after all static constructors have 
 been completed, so that the modules being tested have been initialized?

Fixed.
 But what exactly is the use case here? To just run the unit tests and 
 avoid running main()?
 Wouldn't that be more easily accomplished by just letting the unit tests 
 run "manually" and providing an empty main()?
 Of course, that wouldn't provide as nice an example of flectioned use :P .

Normaly the first failing unittest would terminate the programm, unittest_walker however executes all unittests and displays their failure/success. Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFF/WDHLK5blCcjpWoRApitAJ9pcL+SBhFasCR0OsYzwFP3z5gP7ACfdW77 4EtvBlKRjhcsqCdPmWyuDR0= =M526 -----END PGP SIGNATURE-----
Mar 18 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Thomas Kuehne wrote:
 
 Frits van Bommel schrieb am 2007-03-17:
 Shouldn't unit tests be performed after all static constructors have 
 been completed, so that the modules being tested have been initialized?

Fixed.

Interesting solution, just replacing the _moduleUnitTests() that normally runs them :). (I guess that's the natural place to put it though) Unfortunate about the ugly warning this produces ("usr/bin/ld: Warning: size of symbol `_moduleUnitTests' changed from 1084 in unittest_walker.o to 58 [...]").
 But what exactly is the use case here? To just run the unit tests and 
 avoid running main()?
 Wouldn't that be more easily accomplished by just letting the unit tests 
 run "manually" and providing an empty main()?
 Of course, that wouldn't provide as nice an example of flectioned use :P .

Normaly the first failing unittest would terminate the programm, unittest_walker however executes all unittests and displays their failure/success.

Ah yes, forgot about that (failed unit tests aborting the program). About your sample.d: It thinks I'm a Windows user who didn't compile Phobos with debug symbols :P. In reality, I'm using GDC 0.23 on amd64 Linux. It turns out GDC's std/math.d only declares isnormal() itself if on x86, otherwise it aliases gcc.config.isnormal() to do the job... (Adding "version(GNU) if(!funcs) { funcs = "gcc.config.isnormal" in functions; }" right after the lookup should fix it) Also, your struct example seems to have a typo (0x13_45_67_AB != 0x1234567AB). And some unit tests in flectioned.d fail: --- $ gdmd -L--allow-multiple-definition -fall-sources -unittest -oftest test.d cn/kuehne/flectioned.d cn/kuehne/unittest_walker.d /usr/bin/ld: Warning: size of symbol `_moduleUnitTests' changed from 1084 in unittest_walker.o to 58 in /home/urxae/opt/gdc/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.1.1/../../../../lib64/libgphobos.a(moduleinit.o) $ ./test [snip] testing cn.kuehne.flectioned.TracedException.__unittest21 ... FAILED: (std.asserterror.AssertError) AssertError Failure cn/kuehne/flectioned.d(991) testing cn.kuehne.flectioned.Trace.__unittest18 ... FAILED: (std.asserterror.AssertError) AssertError Failure cn/kuehne/flectioned.d(654) testing cn.kuehne.flectioned.Trace.__unittest19 ... FAILED: (std.asserterror.AssertError) AssertError Failure cn/kuehne/flectioned.d(654) testing cn.kuehne.flectioned.TracedException.__unittest22 ... FAILED: (std.asserterror.AssertError) AssertError Failure cn/kuehne/flectioned.d(654) testing cn.kuehne.flectioned.Trace.__unittest17 ... FAILED: (std.asserterror.AssertError) AssertError Failure cn/kuehne/flectioned.d(654) [snip] Summary: 29/5/34 (succeeded/failed/total) --- (test.d contains only an empty main())
Mar 18 2007
parent reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Frits van Bommel schrieb am 2007-03-18:
[snip]
 About your sample.d: It thinks I'm a Windows user who didn't compile 
 Phobos with debug symbols :P.
 In reality, I'm using GDC 0.23 on amd64 Linux.
 It turns out GDC's std/math.d only declares isnormal() itself if on x86, 
 otherwise it aliases gcc.config.isnormal() to do the job...
 (Adding "version(GNU) if(!funcs) { funcs = "gcc.config.isnormal" in 
 functions; }" right after the lookup should fix it)

 Also, your struct example seems to have a typo (0x13_45_67_AB != 
 0x1234567AB).

Fixed
 And some unit tests in flectioned.d fail:
 ---
 $ gdmd -L--allow-multiple-definition -fall-sources -unittest -oftest 
 test.d cn/kuehne/flectioned.d cn/kuehne/unittest_walker.d
 /usr/bin/ld: Warning: size of symbol `_moduleUnitTests' changed from 
 1084 in unittest_walker.o to 58 in 
 /home/urxae/opt/gdc/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.1.1/../../../../lib64/libgphobos.a(moduleinit.o)
 $ ./test
 [snip]
 testing cn.kuehne.flectioned.TracedException.__unittest21 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(991)

 testing cn.kuehne.flectioned.Trace.__unittest18 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(654)
 testing cn.kuehne.flectioned.Trace.__unittest19 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(654)
 testing cn.kuehne.flectioned.TracedException.__unittest22 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(654)
 testing cn.kuehne.flectioned.Trace.__unittest17 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(654)

Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFF/morLK5blCcjpWoRAmceAKCAz1m8nziIv8XGd42L4EurE7qYLwCfUFCn Z/yF3T0DW25wcBmmSF0HmZA= =AvLO -----END PGP SIGNATURE-----
Mar 19 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Thomas Kuehne wrote:
 
 Frits van Bommel schrieb am 2007-03-18:
 And some unit tests in flectioned.d fail:
 ---
 $ gdmd -L--allow-multiple-definition -fall-sources -unittest -oftest 
 test.d cn/kuehne/flectioned.d cn/kuehne/unittest_walker.d
 /usr/bin/ld: Warning: size of symbol `_moduleUnitTests' changed from 
 1084 in unittest_walker.o to 58 in 
 /home/urxae/opt/gdc/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.1.1/../../../../lib64/libgphobos.a(moduleinit.o)
 $ ./test
 [snip]
 testing cn.kuehne.flectioned.TracedException.__unittest21 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(991)


No, still fails if I put it in test.d (and qualify some of the names of static members).
 testing cn.kuehne.flectioned.Trace.__unittest18 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(654)
 testing cn.kuehne.flectioned.Trace.__unittest19 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(654)
 testing cn.kuehne.flectioned.TracedException.__unittest22 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(654)
 testing cn.kuehne.flectioned.Trace.__unittest17 ... FAILED: 
 (std.asserterror.AssertError) AssertError Failure 
 cn/kuehne/flectioned.d(654)


If I comment that assert out, cn.kuehne.flectioned.Trace.__unittest20 (which seems to be the test for Trace.findSymbol, the function whose postcondition contains that assertion) fails with a segfault. However, the first test, that I copied to test.d, now succeeds... (Even though that wasn't the assertion that failed for that test)
Mar 19 2007