www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - More than one main

reply bearophile <bearophileHUGS lycos.com> writes:
I have discussed this is little problem about three years ago; in the meantime
the situation is changed (rdmd has appeared, DMD has grown the -deps switch,
etc).

I have a little module named "modu":

module modu;
import std.stdio;
int foo() {
    return 0;
}
int main() {
    writeln("modu.main");
    return 1;
}


I create a second module named "somemodule", and import just the foo() function
from mod:

module somemodule;
import std.stdio;
import modu: foo;
int main() {
    writeln("somemodule.main");
    return foo();
}

Now if I compile somemodule normally, with:

rdmd somemodule.d

I receive an error like:

OPTLINK (R) for Win32  Release 8.00.12
Copyright (C) Digital Mars 1989-2010  All rights reserved.
http://www.digitalmars.com/ctg/optlink.html
...   Offset 00137H Record Type 00C3 
 Error 1: Previous Definition Different : __Dmain
--- errorlevel 1


To avoid this problem in Python there is a common idiom:

if __name__ == '__main__':
    # main code here...
    

This idiom allows to define and run a "main" only for the main module.
Currently in D there is no notion of "main module", but I see a simple way to
avoid this problem in D too, defining a new standard version name that tools
like rdmd, bud, etc define for just the first module (like for the only module
name given to rdmd), and don't define for all other modules found and compiled
recursively:

module mod;
int foo() {
    return 0;
}
version (main_module) int main() {
    return 1;
}


The usage of main_module is optional.

I like to keep a main() in most modules, even the ones that are usually not
supposed to be the main modules of a program, because I put in their main()
some demo code that shows what this module does (and a main is useful to run
unittests too, rdmd has the --main switch for this). Most of my Python modules
have such demo main code, that runs only if you run them as main modules.

Bye,
bearophile
Mar 24 2011
next sibling parent reply spir <denis.spir gmail.com> writes:
On 03/24/2011 12:07 PM, bearophile wrote:
 I have discussed this is little problem about three years ago; in the meantime
the situation is changed (rdmd has appeared, DMD has grown the -deps switch,
etc).

 I have a little module named "modu":

 module modu;
 import std.stdio;
 int foo() {
      return 0;
 }
 int main() {
      writeln("modu.main");
      return 1;
 }


 I create a second module named "somemodule", and import just the foo()
function from mod:

 module somemodule;
 import std.stdio;
 import modu: foo;
 int main() {
      writeln("somemodule.main");
      return foo();
 }

 Now if I compile somemodule normally, with:

 rdmd somemodule.d

 I receive an error like:

 OPTLINK (R) for Win32  Release 8.00.12
 Copyright (C) Digital Mars 1989-2010  All rights reserved.
 http://www.digitalmars.com/ctg/optlink.html
 ...   Offset 00137H Record Type 00C3
   Error 1: Previous Definition Different : __Dmain
 --- errorlevel 1


 To avoid this problem in Python there is a common idiom:

 if __name__ == '__main__':
      # main code here...


 This idiom allows to define and run a "main" only for the main module.
Currently in D there is no notion of "main module", but I see a simple way to
avoid this problem in D too, defining a new standard version name that tools
like rdmd, bud, etc define for just the first module (like for the only module
name given to rdmd), and don't define for all other modules found and compiled
recursively:

 module mod;
 int foo() {
      return 0;
 }
 version (main_module) int main() {
      return 1;
 }


 The usage of main_module is optional.

 I like to keep a main() in most modules, even the ones that are usually not
supposed to be the main modules of a program, because I put in their main()
some demo code that shows what this module does (and a main is useful to run
unittests too, rdmd has the --main switch for this). Most of my Python modules
have such demo main code, that runs only if you run them as main modules.

I support finding a solution for this issue. Very annoying esp. during development since running unittests on a module, or set of modules, requires a main() func. But the module(s) one needs to run the unittests of are not always (conceptualy) the main app's module; there may even be none, if it's a lib. So, we need stupidly need to add a fake & empty main() func -- that will later generate linking error when building the whole app ;-) But I do not like your solution, which i find uselessly complicated. In order of preference: * the linker automatically adds an empty main() to the first module if needed * allow empty main() in every module, more than one beeing just ignored * your solution Denis -- _________________ vita es estrany spir.wikidot.com
Mar 24 2011
parent Jacob Carlborg <doob me.com> writes:
On 2011-03-24 14:05, spir wrote:
 On 03/24/2011 12:07 PM, bearophile wrote:
 I have discussed this is little problem about three years ago; in the
 meantime the situation is changed (rdmd has appeared, DMD has grown
 the -deps switch, etc).

 I have a little module named "modu":

 module modu;
 import std.stdio;
 int foo() {
 return 0;
 }
 int main() {
 writeln("modu.main");
 return 1;
 }


 I create a second module named "somemodule", and import just the foo()
 function from mod:

 module somemodule;
 import std.stdio;
 import modu: foo;
 int main() {
 writeln("somemodule.main");
 return foo();
 }

 Now if I compile somemodule normally, with:

 rdmd somemodule.d

 I receive an error like:

 OPTLINK (R) for Win32 Release 8.00.12
 Copyright (C) Digital Mars 1989-2010 All rights reserved.
 http://www.digitalmars.com/ctg/optlink.html
 ... Offset 00137H Record Type 00C3
 Error 1: Previous Definition Different : __Dmain
 --- errorlevel 1


 To avoid this problem in Python there is a common idiom:

 if __name__ == '__main__':
 # main code here...


 This idiom allows to define and run a "main" only for the main module.
 Currently in D there is no notion of "main module", but I see a simple
 way to avoid this problem in D too, defining a new standard version
 name that tools like rdmd, bud, etc define for just the first module
 (like for the only module name given to rdmd), and don't define for
 all other modules found and compiled recursively:

 module mod;
 int foo() {
 return 0;
 }
 version (main_module) int main() {
 return 1;
 }


 The usage of main_module is optional.

 I like to keep a main() in most modules, even the ones that are
 usually not supposed to be the main modules of a program, because I
 put in their main() some demo code that shows what this module does
 (and a main is useful to run unittests too, rdmd has the --main switch
 for this). Most of my Python modules have such demo main code, that
 runs only if you run them as main modules.

I support finding a solution for this issue. Very annoying esp. during development since running unittests on a module, or set of modules, requires a main() func. But the module(s) one needs to run the unittests of are not always (conceptualy) the main app's module; there may even be none, if it's a lib. So, we need stupidly need to add a fake & empty main() func -- that will later generate linking error when building the whole app ;-) But I do not like your solution, which i find uselessly complicated. In order of preference: * the linker automatically adds an empty main() to the first module if needed * allow empty main() in every module, more than one beeing just ignored * your solution Denis

Doesn't rdmd have an option to add a main function? -- /Jacob Carlborg
Mar 24 2011
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
bearophile Wrote:

 I put in their main() some demo code that shows what this module does (and a
main is useful to run unittests too, rdmd has the --main switch for this). Most
of my Python modules have such demo main code, that runs only if you run them
as main modules.
 

unittests should be able to be a demo code for the module. Sometimes they say that unittests do demonstrate, how the module should work.
Mar 24 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
spir:

Very annoying esp. during development since running unittests on a module, or
set of modules, requires a main() func.<

This is not so bad, because rdmd has a --main switch.
* the linker automatically adds an empty main() to the first module if needed<

The linker probably has zero knowledge of what a "first module" is.
* allow empty main() in every module, more than one beeing just ignored<

I don't need just empty mains, I need demo code in them. ------------------------------ Jacob Carlborg:
 Doesn't rdmd have an option to add a main function?

Right, I have said it in my original post too. ------------------------------ Kagamin:
 unittests should be able to be a demo code for the module. Sometimes they say
that unittests do demonstrate, how the module should work.<

For me the code inside unittests and the demo code inside the main (and the functions called just by the main) have different purposes. A demo may open a GUI, interact on the command line with the user, allow the module to be used stand alone with some kind of little interface, show graphs on the screen, etc. While unittests are mostly to test the module is working correctly and they are not supposed to be interactive or to be show graphs, etc. One my real example: in a module that plots functions on the screen, in the main I generate and show some function plots to the user. This is not done in unittests. Bye, bearophile
Mar 24 2011
parent reply Kagamin <spam here.lot> writes:
bearophile Wrote:

 Kagamin:
 
 unittests should be able to be a demo code for the module. Sometimes they say
that unittests do demonstrate, how the module should work.<

For me the code inside unittests and the demo code inside the main (and the functions called just by the main) have different purposes. A demo may open a GUI, interact on the command line with the user, allow the module to be used stand alone with some kind of little interface, show graphs on the screen, etc. While unittests are mostly to test the module is working correctly and they are not supposed to be interactive or to be show graphs, etc. One my real example: in a module that plots functions on the screen, in the main I generate and show some function plots to the user. This is not done in unittests.

you can switch on version matching the module name, or something similar that will be easy to switch in a makefile. module modu; version(modu) void main() { //... }
Mar 24 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Kagamin:

 you can switch on version matching the module name, or something similar that
will be easy to switch in a makefile.
 
 module modu;
 version(modu)
 void main()
 {
   //...
 }

I have explained Walter why that's not good: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=132693 Bye, bearophile
Mar 24 2011
parent Kagamin <spam here.lot> writes:
bearophile Wrote:

 I have explained Walter why that's not good:
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=132693
 

Mar 24 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
 I have discussed this is little problem about three years ago; in the
 meantime the situation is changed (rdmd has appeared, DMD has grown the
 -deps switch, etc).
 
 I have a little module named "modu":
 
 module modu;
 import std.stdio;
 int foo() {
     return 0;
 }
 int main() {
     writeln("modu.main");
     return 1;
 }
 
 
 I create a second module named "somemodule", and import just the foo()
 function from mod:
 
 module somemodule;
 import std.stdio;
 import modu: foo;
 int main() {
     writeln("somemodule.main");
     return foo();
 }
 
 Now if I compile somemodule normally, with:
 
 rdmd somemodule.d
 
 I receive an error like:
 
 OPTLINK (R) for Win32  Release 8.00.12
 Copyright (C) Digital Mars 1989-2010  All rights reserved.
 http://www.digitalmars.com/ctg/optlink.html
 ...   Offset 00137H Record Type 00C3
  Error 1: Previous Definition Different : __Dmain
 --- errorlevel 1
 
 
 To avoid this problem in Python there is a common idiom:
 
 if __name__ == '__main__':
     # main code here...
 
 
 This idiom allows to define and run a "main" only for the main module.
 Currently in D there is no notion of "main module", but I see a simple way
 to avoid this problem in D too, defining a new standard version name that
 tools like rdmd, bud, etc define for just the first module (like for the
 only module name given to rdmd), and don't define for all other modules
 found and compiled recursively:
 
 module mod;
 int foo() {
     return 0;
 }
 version (main_module) int main() {
     return 1;
 }
 
 
 The usage of main_module is optional.
 
 I like to keep a main() in most modules, even the ones that are usually not
 supposed to be the main modules of a program, because I put in their
 main() some demo code that shows what this module does (and a main is
 useful to run unittests too, rdmd has the --main switch for this). Most of
 my Python modules have such demo main code, that runs only if you run them
 as main modules.

I had _never_ heard of anyone ever even sugesting that something like this was an issue until reading about Python. Typically, you have modules which contain code which is called and may or may not be specific to any program, and then you have a module which contains main and _is_ specific to that program. If you want a different program, you just create a new module with a main in it and compile that new program. You don't typically treat modules as runnable in any real sense. They just contain related code. So, honestly, I don't see this as an issue at all. If you _do_ consider to be an issue (as you appear to), then you can just have a function which you put in all of your modules which runs whatever you want to run for that module. Then you just write quick program which calls that module's run function and there you go. But honestly, what you're trying to do just strikes me as plain weird. Maybe it's a typical thing to do in scripting languages, but it definitely isn't in compiled languages. - Jonathan M Davis
Mar 24 2011
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/24/2011 4:07 AM, bearophile wrote:
 I receive an error like:

 OPTLINK (R) for Win32  Release 8.00.12 Copyright (C) Digital Mars 1989-2010
 All rights reserved. http://www.digitalmars.com/ctg/optlink.html ...   Offset
 00137H Record Type 00C3 Error 1: Previous Definition Different : __Dmain ---
 errorlevel 1

No mystery there. You have two main()'s. There can be only one.
 Currently in D there is no notion of "main module",

Yes, there is. It's the one that defines main().
 I like to keep a main() in most modules, even the ones that are usually not
 supposed to be the main modules of a program, because I put in their main()
 some demo code that shows what this module does (and a main is useful to run
 unittests too, rdmd has the --main switch for this). Most of my Python
 modules have such demo main code, that runs only if you run them as main
 modules.

That's what the version statement is for: version (My_Demo) { void main() { ... } } There's no reason to add more features to duplicate that.
Mar 24 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 But honestly, what you're trying to do just strikes me as plain weird. Maybe
 it's a typical thing to do in scripting languages, but it definitely isn't in
 compiled languages.

It's very common in well designed Python modules. Probably you don't see it in compiled languages like C/C++ because they don't have a good module system. D has modules related to Python ones, so I am using this Python idiom in D too. Most D1 modules of dlibs1 have demo code :-) --------------------------- Walter:
 That's what the version statement is for:
 
 version (My_Demo)
 {
      void main()
      {
          ...
      }
 }
 
 There's no reason to add more features to duplicate that.

I too have suggested to use the version() statement, but My_Demo is not a _standard_ version generated automatically by tools like rdmd. In a project you usually use many modules, and some of them have demo code in their main. If you use rdmd or similar tools, you want only one of those mains to be compiled, the right one. Bye, bearophile
Mar 24 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/24/2011 11:47 AM, bearophile wrote:
 I too have suggested to use the version() statement, but My_Demo is not a
 _standard_ version generated automatically by tools like rdmd. In a project
 you usually use many modules, and some of them have demo code in their main.
 If you use rdmd or similar tools, you want only one of those mains to be
 compiled, the right one.

rdmd takes command line switches, which you can use to set the version for which main you want.
Mar 24 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Walter:

 rdmd takes command line switches, which you can use to set the version for
which 
 main you want.

You are missing the point still, I was talking about a single standard version that works in all cases. Here is an example. I have a project (program) P, it contains many modules, its main is inside the module M. Among the modules used by P there are the general-purpose modules A, B, C, D. The modules B and C and D contain a main with demo code. The module A imports the module B, and the module D important C and a less commonly useful module E that has no main and no demo. Now I want to compile the program P with a helper, so it has to compile the main contained inside M. I use: rdmd --build-only M.d rdmd defined a version named like main_module for just the module M.d, so only its main gets compiled. Later I want to try the demos inside A, I use: rdmd A.d Now main_module is defined only for the module A.d and it's not defined inside the module B that A has required rdmd to compile. So only the main of A.d gets compiled. If I use a single My_Demo inside every module M, A, B, C, D, and I give: rdmd -version=My_Demo --build-only M.d Then all mains are visible and the linker gives the error. Similar things happen if I use this, because both the main of A and B are active: rdmd -version=My_Demo A.d If I use a different version for each module, like My_Demo_A inside A.d, My_Demo_B inside B.d, etc, I then later have to compile the code like this: rdmd -version=My_Demo_M --build-only M.d rdmd -version=My_Demo_A A.d This works, but is not as handy as what I have asked. And I have stressed the word _standard_ because a version like My_Demo_M becomes a convention just of my code, while my point was the usefulness of a standard that's supposed to work with other build tools too, etc, so if I take some D modules from another person I don't later have to use all different version names like: rdmd -version=My_NiceDemo_foo foo_bar.d A standard solution avoids this. Bye, bearophile
Mar 24 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
 Jonathan M Davis:
 But honestly, what you're trying to do just strikes me as plain weird.
 Maybe it's a typical thing to do in scripting languages, but it
 definitely isn't in compiled languages.

It's very common in well designed Python modules. Probably you don't see it in compiled languages like C/C++ because they don't have a good module system. D has modules related to Python ones, so I am using this Python idiom in D too. Most D1 modules of dlibs1 have demo code :-)

I really don't understand what you're trying to do with a module "demo." The unit tests test the code in the module. They also provide examples on how to use the code in the module. Also, well-written modules have good examples in their documentation (which is generally tested in the unit tests as well). What is a module demo supposed to achieve that good unit tests and documentation don't? - Jonathan M Davis
Mar 24 2011