www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D modules/sourcecode organisation/filesystem mapping

reply FunkyM <FunkyM_member pathlink.com> writes:
Getting to know D can roughly be compared to seeing light in the darkness. 

It appeared to me that the design of the language followed strict logic patterns
and enjoyable it solved cavejards of problems of other languages.

Next step was to evaluate it for use in commercial projects and spotting any
weakness it might have when starting to use it for a mid-sized project.

Surprisingly, it appeared to solve any assumed weak points itself, again
reflecting
it's really geniously designed semantics.

In affect, the D programming language seems as a good candidate to challenge the
upper mainstream competitiors and from what I see in the community there are
quite
a lot of people who forsee this aswell. It sure has a lot of potential (also
making
Walter Bright an "asked for" legend for businesses migrating to D in all areas).

Aside from the language design itself, first of all the overall "marketing" of
the language needs to "grow up" finally (intuitive web presence,
public repository for gdc, ...) in order to make more people aware of it.

Without a commercial backup, community efforts for this are already ongoing
(some in "secret" groups) to make this happen; some more, some less promising.

However, afterall I found an issue which I think will have an impact in this 
development of the language at some point, primary as soon as common big-sized
frameworks with extended API's are created using D (relates to Ares, Mango etc.
aswell).

It also has an impact on deciding to use D in some of my projects and the
decision to dedicate extended resources to help D's development/marketshare.

This most likely has not yet strived the round as it was not really a
requirement
for most small "libs" which act more like an utility than reaching a degree of 
complex frameworks and the current system was sufficient or basicly just taken
as-is.

# Issue:

D provides solutions to almost any "logic" weakness you could possibly find in
other languages and "counters" attempts to find them in D itself.

The D specification defines several goals and rules to base it's design on.
However, some of the rules fail especially on the main topic of my post:

 D and module/sourcecode organisation/filesystem-to-module-mapping <<


# The "module" approach reveales the following weakness list: - Not possible to have unlimited package hierarchies (There is an "all.d" usage hack, D should practically NOT require "hacks"...) - Porting bigger projects is not possible without introducing API changes - Prevents creation of maintainable applications/frameworks/libraries (req. for future of D!) - Spltting up a bigger module file does break your API (see below) - Adds additional unrequired package levels (notice this in MANY places, e.g.: gtk.window.Window vs. gtk.Window) - Bad maintainability if lots of classes are implemented in one module - Ambigious "non-intuitive" API design rules for developers migrating to D - Prevents splitting big sources into multiple files efficiently - It only succeedes on old-fashioned "flat-hierarchy" C style "utility libraries" (Yes you can write big libraries; efficient/logical for a powerful OO language?) - Limits/forces the developer indirectly to design "flat" libraries (think of intuitive descriptive/naming needs in many cases) These issues regarding mappings have been noticed on several occasions while working with the D language primary in attempts to create application frameworks such as the DFL GUI library, DUIT Gtk Library, x-2-D language converters or similar libraries. In those cases either a big module file is used or an additional duplicated package level has been introduced. The authors of these WELCOME a proper solution if one would exist. Some people are not even aware of these limitations yet but "intentionally" propose module hierarchies that would not work due current limitations. It is often an issue for projects in their initial design state or once they get a lot of classes, alongside their implementation, in one single module file, then attempting to split them into individual modules. Neither is it very efficient nor practicable from the programmers point of view. # Why this is significantly important/What would it improve: The argument set "modules are just simpler and better" is logically very weak if compared to the other arguments used in all other areas of D's specification. Modules do not solve the discussed issues nor stand to the modern "namespace" element's functionality. The requirement for D not to fail for serious complex development problems and adapting modern approaches for maintable efficient API design is an requirement for it's future ranking for being picked as the language for various projects either for proprietary or open source projects with many developers. (Imagine revision control systems on big source files) Designing a cross-platform GUI library would suffer on these limitations. Simple example: -> Imaging you have such a structure: system.drawing.SomeEnum.TOP -> /system/drawing.d system.drawing.Bitmap -> /system/drawing.d system.drawing.Brush -> /system/drawing.d .. -> At some point drawing.d becomes big/unmaintainable -> split sources system.drawing.SomeEnum.TOP -> CURRENTLY IMPOSSIBLE: packagename != modulename system.drawing.bitmap.Bitmap -> /system/drawing/bitmap.d with add. package lvl system.drawing.brush.brush -> /system/drawing/brush.d with add. package lvl .. # No critic without... a potential solution: After trying a couple of things it was hard to still be compliant to the D goals/rules while providing a solution that is backwards compatible to current D projects to avoid a need for re-write while still adding the required functionality and not increasing compiler complexity significantly (such as the namespace feature would). Surprisingly, after various attempts, the solution resulted to be simple, yet needs verifications from various other people on this list. Especially after reading a post issuing that this is possible: "foo.d: module bar; ..." "foobar.d: import foo; void main(..." This example showed that the "internals" of the compiler would already be able to compensate for the required changes solving the presented weakness. # Proposal "Solution A": Introduce/change rules: 1) Remove the limitation that a packagename can not be a modulename 2) Change definition of "module" keyword to "defines the package of the current module" 3) The import statement qualified name maps to the filesystem packages.modulename (4) Optionally rename/change to a better keyword used in this context?) This seems to pass logic and should be possible to implement (as it seems to be indirectly supported already): /gtk.d: module gtk; enum edges { LEFT, RIGHT, TOP, BOTTOM } .. /gtk/window.d: module gtk; class Window { .. mainapp.d: import gtk; import gtk.window; // Get's ./gtk/window.d and maps it into package gtk .. As of now you could already get your gtk.Window qualification if you would just put everything into the "gtk.d" module, the final result would be identical to that of the example above. The proposal, while still maintaining the current way of loading modules due to imports, would make the class Window to be qualified as gtk.Window leaving a nice API and allowing to structure your source in a maintainable way along a couple of other improvements: # Positive arguments: - After a change, this remains backwards compatible to current libraries (I am 100% sure all new projects will use this "natively" automatically and existing projects will migrate asap) - Everything still remains fully qualified and uniquely identificable - Source maintainability is improved allowing splitting source code up into files - Overall change does not break with D's language semantics (nor has direct impact on the language itself) - Simplifies porting existing API's significantly (1:1, helps a couple of existing projects!) - Freedom to choose flat/hierarchic source structuring - Still sticks to use of modules vs. "header/include files" or "nested namespaces" - Allows efficient and modern API design; without overhead package levels - Does not break use of "build" tool (a commonly used tool to aid in compilation) - Spltting up a bigger module file at any time does not break your API Of course it breaks clearly with the rules packagename!=modulename and with the current use of the "module" keyword definition. Both favoured to be dropped when compared to the extended functionality and simplification you get from doing so. Mind that this is not a shoutout for heating up a "namespace" discussion as a solution, as such stuff probably adds significant overhead to the compiler. Neither I don't hope for getting "D is not Java/C#" arguments here as I am aware of the design intentions of D; rather objective discussions on this topic. This post is clearly requesting community VOTES for fixing this issue, possibly but not necessarly using the presented solution. I encourage anyone to propose a logical efficient solution apart from mine. Even just sharing your thoughts if you ran into similar limitations yourself. I am a fan of modern, standards compliant, logical and efficient approaches and very eager for the D language to succeed and get constructive comments on this. For my part I do not see that D will "jump-over" to adulthood mid-/long-term without a proper fix to the discussed issue and I don't see a better way of bringing this onto the table aside from this list. Thanks for reading all this, I hope it makes sense! :) --- Martin Szulecki
May 10 2006
next sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
FunkyM escribió:
 
 Introduce/change rules:
 
 1) Remove the limitation that a packagename can not be a modulename
 2) Change definition of "module" keyword to "defines the package of the current
 module"
 3) The import statement qualified name maps to the filesystem
 packages.modulename
 (4) Optionally rename/change to a better keyword used in this context?)
 

Maybe it's because I'm already used to how D works, but I find these new rules a bit confusing. Perhaps in time (more posts about it, refining the idea, etc.) they'll become a bit clearer.
 This seems to pass logic and should be possible to implement
 (as it seems to be indirectly supported already):
 
 /gtk.d:
 module gtk;
 
 enum edges { LEFT, RIGHT, TOP, BOTTOM }
 ...
 
 /gtk/window.d:
 module gtk;
 
 class Window {
 ...
 
 mainapp.d:
 
 import gtk;
 import gtk.window; // Get's ./gtk/window.d and maps it into package gtk
 ...
 
 

I think this would be tricky for the compiler. The compiler would know that /gtk/window.d is gtk.window, but how would it know if /gtk.d is just gtk or gtk.gtk? Remember that it's an important decision because of name mangling.
 
 --- Martin Szulecki

Like I said, maybe it's because I'm already used to how D works or maybe I haven't worked in projects that large, but I haven't found the current module system limiting. I think the worst thing about it is when you import two modules which have the same function defined and then the compiler complains about which one you want to call, and that's not even a problem of modules but of D rules about resolving names. And anyway, it's not that difficult to write a couple of aliases to get around it. -- Carlos Santander Bernal
May 10 2006
parent reply FunkyM <FunkyM_member pathlink.com> writes:
In article <e3tsie$2adt$1 digitaldaemon.com>, Carlos Santander says...
FunkyM escribió:
 
 Introduce/change rules:
 
 1) Remove the limitation that a packagename can not be a modulename
 2) Change definition of "module" keyword to "defines the package of the current
 module"
 3) The import statement qualified name maps to the filesystem
 packages.modulename
 (4) Optionally rename/change to a better keyword used in this context?)
 

Maybe it's because I'm already used to how D works, but I find these new rules a bit confusing. Perhaps in time (more posts about it, refining the idea, etc.) they'll become a bit clearer.

Yeah, infact it is a basic change mainly on the "module" keyword. My "extended" explaination might be a bit too much information on one shot. Right now you for a file "/foo/bar.d" you would have to write "module foo.bar;" and you can NOT have a file "/foo.d" with "module foo;". These changes make it possible to say "module foo;" in "/foo/bar.d" and use "/foo.d" with "module foo;" which results in "merging" the two scopes. Nothing changes regarding how "import" works, basicly ignore 3) if you want and 4) relates to the "module" keyword.
 This seems to pass logic and should be possible to implement
 (as it seems to be indirectly supported already):
 
 /gtk.d:
 module gtk;
 
 enum edges { LEFT, RIGHT, TOP, BOTTOM }
 ...
 
 /gtk/window.d:
 module gtk;
 
 class Window {
 ...
 
 mainapp.d:
 
 import gtk;
 import gtk.window; // Get's ./gtk/window.d and maps it into package gtk
 ...
 
 

I think this would be tricky for the compiler. The compiler would know that /gtk/window.d is gtk.window, but how would it know if /gtk.d is just gtk or gtk.gtk? Remember that it's an important decision because of name mangling.

import gtk; -> ./gtk.d import gtk.gtk -> ./gtk/gtk.d There is no change in the import loading behaviour due to my proposal. However, I wonder why already two people have "misinterpreted" it. Infact, it's not tricky, it is the already used mechanism.
 
 --- Martin Szulecki

Like I said, maybe it's because I'm already used to how D works or maybe I haven't worked in projects that large, but I haven't found the current module system limiting. I think the worst thing about it is when you import two modules which have the same function defined and then the compiler complains about which one you want to call, and that's not even a problem of modules but of D rules about resolving names. And anyway, it's not that difficult to write a couple of aliases to get around it.

As I noted, for some people those limitations won't be the "rock in the eye" and they will still be able to create projects as they like (build their games etc.) with how D is working now. However, there will be a point in mid-/long-term that will heavily define D's future upon this issue and for me it is already one. It might take experience in the "other" languages C++/Java/C#/(any other high level OOPL) and maybe some farsight to draw the lines. I guess it will only be instantly obvious for people who stumbled among the same limitations when coming from pure D. (and totally not seen as required from C purists ;) Conflicts are not different in my approach as they are now. You can't have two functions/classes/(elements) at the same scope. Aliases "hacking" along with the "all.d" hack have been proposed to me. I think one goal of D which sets it apart from other languages is to not require such hacks and work intuitive and practical. The alias "trick" didn't work in this case as the compiler does break out on compilation. It seems like unable to alias longer fully qualified names correctly. Anyways, that would not solve the issues I listed either and add more ambigious overhead. --- Martin Szulecki
May 11 2006
next sibling parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
FunkyM wrote:

Like I said, maybe it's because I'm already used to how D works or maybe I 
haven't worked in projects that large, but I haven't found the current module 
system limiting. I think the worst thing about it is when you import two
modules 
which have the same function defined and then the compiler complains about
which 
one you want to call, and that's not even a problem of modules but of D rules 
about resolving names. And anyway, it's not that difficult to write a couple of 
aliases to get around it.

As I noted, for some people those limitations won't be the "rock in the eye" and they will still be able to create projects as they like (build their games etc.) with how D is working now. However, there will be a point in mid-/long-term that will heavily define D's future upon this issue and for me it is already one. It might take experience in the "other" languages C++/Java/C#/(any other high level OOPL) and maybe some farsight to draw the lines. I guess it will only be instantly obvious for people who stumbled among the same limitations when coming from pure D. (and totally not seen as required from C purists ;)

There is something related in the wxD project, with the wxD class names: (there's a long list at http://wxd.sourceforge.net/docs/annotated.html) in C++, it is called "wxWindow". (avoiding namespaces) "<wx/window.h>" http://www.wxwidgets.org/manuals/2.6.3/wx_wxwindow.html in C#, it is called "wx.Window". (using namespace: wx) in "Window.cs" http://wxnet.sourceforge.net/apiref/wx/Window.html in D, it is called "wx.Window.Window" (because code is in "Window.d") http://wxd.sourceforge.net/api/classwx_1_1_window_1_1_window.html As a side note, we're using "import wx.wx;" to import every wxD module. And after you've imported that, you can use a short name like "Window". --anders
May 11 2006
prev sibling next sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
FunkyM escribió:
 In article <e3tsie$2adt$1 digitaldaemon.com>, Carlos Santander says...
 FunkyM escribió:
 This seems to pass logic and should be possible to implement
 (as it seems to be indirectly supported already):

 /gtk.d:
 module gtk;

 enum edges { LEFT, RIGHT, TOP, BOTTOM }
 ...

 /gtk/window.d:
 module gtk;

 class Window {
 ...

 mainapp.d:

 import gtk;
 import gtk.window; // Get's ./gtk/window.d and maps it into package gtk
 ...

/gtk/window.d is gtk.window, but how would it know if /gtk.d is just gtk or gtk.gtk? Remember that it's an important decision because of name mangling.

import gtk; -> ./gtk.d import gtk.gtk -> ./gtk/gtk.d There is no change in the import loading behaviour due to my proposal. However, I wonder why already two people have "misinterpreted" it. Infact, it's not tricky, it is the already used mechanism.

I wasn't talking about import, I was talking about mangling names in an object file. When the compiler generates the object file, how does it know if a member belongs to the module gtk or gtk.gtk? Because for one module (gtk.window) you're prepending the package name but for the other you're not. Will it generate _D3gtk3fooi or _D3gtk3gtk3fooi? (those names are from memory and just examples) -- Carlos Santander Bernal
May 11 2006
parent reply FunkyM <FunkyM_member pathlink.com> writes:
In article <e3vc41$1b5g$1 digitaldaemon.com>, Carlos Santander says...
FunkyM escribió:
 In article <e3tsie$2adt$1 digitaldaemon.com>, Carlos Santander says...
 FunkyM escribió:
 This seems to pass logic and should be possible to implement
 (as it seems to be indirectly supported already):

 /gtk.d:
 module gtk;

 enum edges { LEFT, RIGHT, TOP, BOTTOM }
 ...

 /gtk/window.d:
 module gtk;

 class Window {
 ...

 mainapp.d:

 import gtk;
 import gtk.window; // Get's ./gtk/window.d and maps it into package gtk
 ...

/gtk/window.d is gtk.window, but how would it know if /gtk.d is just gtk or gtk.gtk? Remember that it's an important decision because of name mangling.

import gtk; -> ./gtk.d import gtk.gtk -> ./gtk/gtk.d There is no change in the import loading behaviour due to my proposal. However, I wonder why already two people have "misinterpreted" it. Infact, it's not tricky, it is the already used mechanism.

I wasn't talking about import, I was talking about mangling names in an object file. When the compiler generates the object file, how does it know if a member belongs to the module gtk or gtk.gtk? Because for one module (gtk.window) you're prepending the package name but for the other you're not. Will it generate _D3gtk3fooi or _D3gtk3gtk3fooi? (those names are from memory and just examples)

I still have trouble to fully understand why you check gtk vs gtk.gtk. Assuming you try to point out a possible problem when multiple package levels have the same name, after having name mangling applied. The compiler generates (I made a simple test to verify) the one dependent on your qualification like this: /gtk.d -> _D3gtk5fooi /gtk/gtk.d -> _D3gtk3gtk5fooi /gtk/window.d -> _D3gtk5fooi (since the file used "module gtk;") That does not look problematic to me regarding locating which member belongs to which package? (Did I overlooked something?) Now I think all the implementation seems more and more trivial and somehow reflects the "already indirectly supported" stuff showing up. --- Martin Szulecki
May 12 2006
parent Carlos Santander <csantander619 gmail.com> writes:
FunkyM escribió:
 
 I still have trouble to fully understand why you check gtk vs gtk.gtk.
 Assuming you try to point out a possible problem when multiple package levels
 have the same name, after having name mangling applied.
 

Consistency. In /gtk.d you're asking the compiler to treat it just as gtk, but in /gtk/window.d you're asking it to be gtk.window. So, if the rules are not clearly defined, the compiler could think that /gtk.d is gtk.gtk.
 The compiler generates (I made a simple test to verify) the one dependent on
 your qualification like this:
 
 /gtk.d        -> _D3gtk5fooi
 /gtk/gtk.d    -> _D3gtk3gtk5fooi
 /gtk/window.d -> _D3gtk5fooi (since the file used "module gtk;")
 
 That does not look problematic to me regarding locating which member belongs to
 which package? (Did I overlooked something?)
 
 Now I think all the implementation seems more and more trivial and somehow
 reflects the "already indirectly supported" stuff showing up.
 

I'm not really sure about what you did because you're using "module" in a different way than it's supposed to be right now. Anyway, try this: add /gtk/button.d (or whatever) and also use in it "module gtk;". Now try to compile button and window, and pretty sure the compiler will give you an error message (module gtk is multiple defined, or something like that).
 --- Martin Szulecki

-- Carlos Santander Bernal
May 12 2006
prev sibling parent reply Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
FunkyM wrote:
 
 Yeah, infact it is a basic change mainly on the "module" keyword. My "extended"
 explaination might be a bit too much information on one shot.
 
 Right now you for a file "/foo/bar.d" you would have to write "module foo.bar;"
 and you can NOT have a file "/foo.d" with "module foo;".
 
 These changes make it possible to say "module foo;" in "/foo/bar.d" and use
 "/foo.d" with "module foo;" which results in "merging" the two scopes.
 

What happens when both "module foo;"'s have module constructors/destructors ? -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
May 12 2006
next sibling parent FunkyM <FunkyM_member pathlink.com> writes:
In article <e42g7v$2pfk$1 digitaldaemon.com>, Bruno Medeiros says...
FunkyM wrote:
 
 Yeah, infact it is a basic change mainly on the "module" keyword. My "extended"
 explaination might be a bit too much information on one shot.
 
 Right now you for a file "/foo/bar.d" you would have to write "module foo.bar;"
 and you can NOT have a file "/foo.d" with "module foo;".
 
 These changes make it possible to say "module foo;" in "/foo/bar.d" and use
 "/foo.d" with "module foo;" which results in "merging" the two scopes.
 

What happens when both "module foo;"'s have module constructors/destructors ?

Not absolutely sure about that. If the changes for the "solution" would get applied, I guess by roughly judging from the DMD frontend sources, the static constructors/destructors would get called per "module file". Their order in that case remains: "The order of static initialization is implicitly determined by the import declarations in each module.", as from D language spec and judged by DMD frontend sources. (In above scenario you still write "import foo, foo.bar;") I am trying myself in altering the DMD frontend adding my proposal in order to strive upon all impacts of a change. This is sure one to be discussed/defined. --- Martin Szulecki
May 12 2006
prev sibling next sibling parent Sean Kelly <sean f4.ca> writes:
Bruno Medeiros wrote:
 FunkyM wrote:
 Yeah, infact it is a basic change mainly on the "module" keyword. My 
 "extended"
 explaination might be a bit too much information on one shot.

 Right now you for a file "/foo/bar.d" you would have to write "module 
 foo.bar;"
 and you can NOT have a file "/foo.d" with "module foo;".

 These changes make it possible to say "module foo;" in "/foo/bar.d" 
 and use
 "/foo.d" with "module foo;" which results in "merging" the two scopes.

What happens when both "module foo;"'s have module constructors/destructors ?

My guess is that one of the ctor/dtor pairs would either be thrown out during library assembly (or linking), or that a duplicate symbol error would be generated. I think the 'ld' tool on Linux could be made to do either, but I'm not sure how flexible the Windows tools are. Sean
May 12 2006
prev sibling parent reply Chad J <gamerChad _spamIsBad_gmail.com> writes:
Bruno Medeiros wrote:
 FunkyM wrote:
 
 Yeah, infact it is a basic change mainly on the "module" keyword. My 
 "extended"
 explaination might be a bit too much information on one shot.

 Right now you for a file "/foo/bar.d" you would have to write "module 
 foo.bar;"
 and you can NOT have a file "/foo.d" with "module foo;".

 These changes make it possible to say "module foo;" in "/foo/bar.d" 
 and use
 "/foo.d" with "module foo;" which results in "merging" the two scopes.

What happens when both "module foo;"'s have module constructors/destructors ?

Why not just execute both? Almost makes me wonder, why not have multiple module ctors/dtors in the same file? I tend to use them as a convenient way to execute starttime code. It could be advantageous to be able to place pieces starttime code next to logically related runtime code, instead of lumping it all together at the top of the file or some such.
May 12 2006
parent reply Sean Kelly <sean f4.ca> writes:
Chad J wrote:
 Bruno Medeiros wrote:
 FunkyM wrote:

 Yeah, infact it is a basic change mainly on the "module" keyword. My 
 "extended"
 explaination might be a bit too much information on one shot.

 Right now you for a file "/foo/bar.d" you would have to write "module 
 foo.bar;"
 and you can NOT have a file "/foo.d" with "module foo;".

 These changes make it possible to say "module foo;" in "/foo/bar.d" 
 and use
 "/foo.d" with "module foo;" which results in "merging" the two scopes.

What happens when both "module foo;"'s have module constructors/destructors ?

Why not just execute both? Almost makes me wonder, why not have multiple module ctors/dtors in the same file? I tend to use them as a convenient way to execute starttime code. It could be advantageous to be able to place pieces starttime code next to logically related runtime code, instead of lumping it all together at the top of the file or some such.

No reason not to. Multiple unittests are already allowed. Sean
May 12 2006
parent reply "Derek Parnell" <derek psych.ward> writes:
On Sat, 13 May 2006 09:53:10 +1000, Sean Kelly <sean f4.ca> wrote:

 Chad J wrote:
 Bruno Medeiros wrote:


...
 What happens when both "module foo;"'s have module  
 constructors/destructors ?



  Why not just execute both?  Almost makes me wonder, why not have  
 multiple module ctors/dtors in the same file?


 No reason not to.  Multiple unittests are already allowed.

There are already precedents for this type of coding. Not only the 'unittest' idea but 'scope()' also allows us to physically separate code that is executed linearly. So the concept is not foreign to D or Walter. -- Derek Parnell Melbourne, Australia
May 10 2006
parent reply Chad J <gamerChad _spamIsBad_gmail.com> writes:
Derek Parnell wrote:
 
 
 There are already precedents for this type of coding. Not only the  
 'unittest' idea but 'scope()' also allows us to physically separate 
 code  that is executed linearly. So the concept is not foreign to D or 
 Walter.
 

While I'm at it, I'd also like to see the ability to set a variable to the result of some function at starttime, like so: int[] squares = initSquares(); int[] initSquares() { int[] result = new int[20]; for ( int i = 0; i < 20; i++ ) result[i] = i * i; return result; } void main() { char[] testStr; for ( int i = 0; i < squares.length; i++ ) testStr ~= toString(i)~" squared is "~toString( squares[i] ) ~ "\n"; writefln( testStr ); } This is something I used in C# and enjoyed. Any particular reason this doesn't exist already? Maybe I am supposed to write my code a different way, if so please enlighten me. My current workaround is to use static ctors, but that doesn't seem as readable to me.
May 12 2006
parent reply Kyle Furlong <kylefurlong gmail.com> writes:
Chad J wrote:
 Derek Parnell wrote:
 There are already precedents for this type of coding. Not only the  
 'unittest' idea but 'scope()' also allows us to physically separate 
 code  that is executed linearly. So the concept is not foreign to D or 
 Walter.

While I'm at it, I'd also like to see the ability to set a variable to the result of some function at starttime, like so: int[] squares = initSquares(); int[] initSquares() { int[] result = new int[20]; for ( int i = 0; i < 20; i++ ) result[i] = i * i; return result; } void main() { char[] testStr; for ( int i = 0; i < squares.length; i++ ) testStr ~= toString(i)~" squared is "~toString( squares[i] ) ~ "\n"; writefln( testStr ); } This is something I used in C# and enjoyed. Any particular reason this doesn't exist already? Maybe I am supposed to write my code a different way, if so please enlighten me. My current workaround is to use static ctors, but that doesn't seem as readable to me.

This is the natural functional area for template functions. Simply change your code to this: int[20] squares = initSquares!(int, 20)(); template initSquares(T, int C) { T[] initSquares() { T[C] result; for ( int i = 0; i < C; i++ ) result[i] = i * i; return result; } } -- Kyle Furlong // Physics Undergrad, UCSB "D is going wherever the D community wants it to go." - Walter Bright
May 14 2006
parent Derek Parnell <derek psych.ward> writes:
On Sun, 14 May 2006 16:43:08 -0700, Kyle Furlong wrote:

 Chad J wrote:
 Derek Parnell wrote:
 There are already precedents for this type of coding. Not only the  
 'unittest' idea but 'scope()' also allows us to physically separate 
 code  that is executed linearly. So the concept is not foreign to D or 
 Walter.

While I'm at it, I'd also like to see the ability to set a variable to the result of some function at starttime, like so: int[] squares = initSquares(); int[] initSquares() { int[] result = new int[20]; for ( int i = 0; i < 20; i++ ) result[i] = i * i; return result; } void main() { char[] testStr; for ( int i = 0; i < squares.length; i++ ) testStr ~= toString(i)~" squared is "~toString( squares[i] ) ~ "\n"; writefln( testStr ); } This is something I used in C# and enjoyed. Any particular reason this doesn't exist already? Maybe I am supposed to write my code a different way, if so please enlighten me. My current workaround is to use static ctors, but that doesn't seem as readable to me.

This is the natural functional area for template functions. Simply change your code to this: int[20] squares = initSquares!(int, 20)(); template initSquares(T, int C) { T[] initSquares() { T[C] result; for ( int i = 0; i < C; i++ ) result[i] = i * i; return result; } }

Have you actually tried this, Kyle? I understood the issue to be that the only way that D allows one to call a function to initialize a module-scoped static array is during the 'static this()' function. However this means that the declaration and the initialization code are physically separated. I think the OP wanted a mechanism that had the initialization code and the declaration code to be together. Your response was illustrating templates but that is not relevant to the problem at hand. The best I think that one can come up using templates is ... // --------------- code starts ----------- import std.string; import std.stdio; int[] squares; static this() { squares = initSquares!(int, 20); } template initSquares(T, int C) { T[] initSquares() { T[] result = new T[C]; foreach ( int i, inout T item; result ) item = i * i; return result; } } void main() { for ( int i = 0; i < squares.length; i++ ) writefln("%s squared is %s", i, squares[i]); } // --------------- code ends ----------- Still the declaration and initialization are separated. And if one wants to use something other than 'int' you have to change two lines rather than one. What would be *nice* is to have D see ... int squares = initSquares!(int, 20); at the module-level and automatically generate the initialization code to go into the module's ctor. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 15/05/2006 3:28:41 PM
May 14 2006
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 10 May 2006 18:53:32 +0000 (UTC), FunkyM wrote:


...

 
 In affect, the D programming language seems as a good candidate to challenge
the
 upper mainstream competitiors

Yep, no argument there. ...
 
 Introduce/change rules:
 
 1) Remove the limitation that a packagename can not be a modulename

This is an obvious improvement because such a limitation is not intuitive to new comers and is a awkwardly learned one.
 2) Change definition of "module" keyword to "defines the package of the current
 module"

Are you saying then that "module xyz;" means that this file belongs to the package called "xyz"? This could be misleading so maybe a new keyword word (or the 'package' one reused) might be a better way to go.
 3) The import statement qualified name maps to the filesystem
 packages.modulename

Does this mean that "import foo;" tells the compiler to get the file "foo.d" in the current directory, and if that fails get the file "foo.d" in the folder specified by the "module" keyword (xyz/foo.d in this example)?
 (4) Optionally rename/change to a better keyword used in this context?)

Better than 'module'? or better than 'import'?
 This seems to pass logic and should be possible to implement
 (as it seems to be indirectly supported already):
 
 /gtk.d:
 module gtk;
 
 enum edges { LEFT, RIGHT, TOP, BOTTOM }
 ..
 
 /gtk/window.d:
 module gtk;
 
 class Window {
 ..
 
 mainapp.d:
 
 import gtk;

Does this mean first the compiler tries "./gtk.d" and if that fails it tries "gtk/gtk.d" relative to each path in the -I list until it finds it?
 import gtk.window; // Get's ./gtk/window.d and maps it into package gtk

But how do the paths in the -I list figure that algorithm? -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 11/05/2006 10:01:45 AM
May 10 2006
parent FunkyM <FunkyM_member pathlink.com> writes:
In article <16y7y27ax51ei$.fk3ned70zr4e$.dlg 40tude.net>, Derek Parnell says...
On Wed, 10 May 2006 18:53:32 +0000 (UTC), FunkyM wrote:
 Introduce/change rules:
 
 1) Remove the limitation that a packagename can not be a modulename

This is an obvious improvement because such a limitation is not intuitive to new comers and is a awkwardly learned one.

Glad to hear.
 2) Change definition of "module" keyword to "defines the package of the current
 module"

Are you saying then that "module xyz;" means that this file belongs to the package called "xyz"? This could be misleading so maybe a new keyword word (or the 'package' one reused) might be a better way to go.

Yes, "module foo;" says this file belongs to package "foo". I also thought about a new/changed keyword. This relates to 4)
 3) The import statement qualified name maps to the filesystem
 packages.modulename

Does this mean that "import foo;" tells the compiler to get the file "foo.d" in the current directory, and if that fails get the file "foo.d" in the folder specified by the "module" keyword (xyz/foo.d in this example)?

Fortunately it's not different from how it is handled now so I could have just skipped writing 3). The current form is: [package|[.package|...].]module Whereas "package" maps to directory and "module" maps to file. "import foo;" -> compiler gets "./foo.d" in directories of include paths. "import foo.bar;" -> "./foo/bar.d" in directories of include paths.
 (4) Optionally rename/change to a better keyword used in this context?)

Better than 'module'? or better than 'import'?

I am referring to "module" of course regarding 2).
 This seems to pass logic and should be possible to implement
 (as it seems to be indirectly supported already):
 
 /gtk.d:
 module gtk;
 
 enum edges { LEFT, RIGHT, TOP, BOTTOM }
 ..
 
 /gtk/window.d:
 module gtk;
 
 class Window {
 ..
 
 mainapp.d:
 
 import gtk;

Does this mean first the compiler tries "./gtk.d" and if that fails it tries "gtk/gtk.d" relative to each path in the -I list until it finds it?

No, it won't lookup "gtk/gtk.d" at all. It looks up "gtk.d" in "-I".
 import gtk.window; // Get's ./gtk/window.d and maps it into package gtk

But how do the paths in the -I list figure that algorithm?

This looks up "gtk/window.d" in "-I". Note there is no change in the file loading behaviour introduced by my proposal. "import" works as it works right now. Only the "module" keyword's use differs which comes AFTER the "load module file" step. --- Martin Szulecki
May 10 2006
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
FunkyM wrote:
 
 -> Imaging you have such a structure:
 
 system.drawing.SomeEnum.TOP   -> /system/drawing.d
 system.drawing.Bitmap         -> /system/drawing.d
 system.drawing.Brush          -> /system/drawing.d
 ..
 
 -> At some point drawing.d becomes big/unmaintainable -> split sources
 
 system.drawing.SomeEnum.TOP   -> CURRENTLY IMPOSSIBLE: packagename !=
modulename
 system.drawing.bitmap.Bitmap  -> /system/drawing/bitmap.d with add. package lvl
 system.drawing.brush.brush    -> /system/drawing/brush.d with add. package lvl

Technically, I think this is untrue. As the current module declaration allows you to specify both the package and module name, you could actually have multiple files with the same module declaration, compile them separately, and provide a unified header (.di file) to clients with all declarations in it. In other words, the current scheme seems like it could be made to work in a manner much like C/C++ include files with a bit of effort. If the module scheme were to be modified, I think there are two options that may be workable: 1. Change 'module' to 'package' and infer the module name from the file name since that's what is used for 'import' anyway. 2. Have the header file generation option generate files based on the module name, not the file name. Thus this file: // foo.d module a.b.c; would create "a/b/c.di" in the target directory. An extension of this would be to offer some means of appending to the existing file if one existed, so modules could theoretically be broken across multiple files. I'm not sure I entirely like this last idea as it breaks the idea of one file per module, but as you say, it's possible that's actually desirable in very large projects.
 # Proposal "Solution A":
 
 Introduce/change rules:
 
 1) Remove the limitation that a packagename can not be a modulename
 2) Change definition of "module" keyword to "defines the package of the current
 module"
 3) The import statement qualified name maps to the filesystem
 packages.modulename
 (4) Optionally rename/change to a better keyword used in this context?)

As above, I think the current method allows for this sort of thing if you're willing to manually create your own header files. The purpose of the module declaration is to determine the mangled name of symbols in that file, and import necessarily refers to file names rather than module names. So do something like this: // src/a/b/foo.d module a.b; void doFoo() {} // src/a/b/bar.d module a.b; void doBar() {} // include/a/b.di module a.b; void doFoo(); void doBar(); Note that I haven't tried this, but given my understanding of DMD I think it would work. Sean
May 11 2006
parent FunkyM <FunkyM_member pathlink.com> writes:
Great post.

In article <e3vr42$1ths$1 digitaldaemon.com>, Sean Kelly says...
FunkyM wrote:
 
 -> Imaging you have such a structure:
 
 system.drawing.SomeEnum.TOP   -> /system/drawing.d
 system.drawing.Bitmap         -> /system/drawing.d
 system.drawing.Brush          -> /system/drawing.d
 ..
 
 -> At some point drawing.d becomes big/unmaintainable -> split sources
 
 system.drawing.SomeEnum.TOP   -> CURRENTLY IMPOSSIBLE: packagename !=
modulename
 system.drawing.bitmap.Bitmap  -> /system/drawing/bitmap.d with add. package lvl
 system.drawing.brush.brush    -> /system/drawing/brush.d with add. package lvl

Technically, I think this is untrue. As the current module declaration allows you to specify both the package and module name, you could actually have multiple files with the same module declaration, compile them separately, and provide a unified header (.di file) to clients with all declarations in it. In other words, the current scheme seems like it could be made to work in a manner much like C/C++ include files with a bit of effort.

VERY interesting idea. Now if this is working it would actually prove that the idea of splitting sources is infact already supported (check last part, its working). However, of course this approach uses the .di header files in a different sense than they are supposed to be used (roughly, provide a way to not supply the sources) and it introduces C/C++ like header usage requiring to supply your element's definition.
If the module scheme were to be modified, I think there are two options 
that may be workable:

1. Change 'module' to 'package' and infer the module name from the file 
name since that's what is used for 'import' anyway.

2. Have the header file generation option generate files based on the 
module name, not the file name.  Thus this file:

     // foo.d
     module a.b.c;

would create "a/b/c.di" in the target directory.  An extension of this 
would be to offer some means of appending to the existing file if one 
existed, so modules could theoretically be broken across multiple files. 
  I'm not sure I entirely like this last idea as it breaks the idea of 
one file per module, but as you say, it's possible that's actually 
desirable in very large projects.

1. sounds what I actually had in mind with my proposal and it seems as a very practical to me.
 # Proposal "Solution A":
 
 Introduce/change rules:
 
 1) Remove the limitation that a packagename can not be a modulename
 2) Change definition of "module" keyword to "defines the package of the current
 module"
 3) The import statement qualified name maps to the filesystem
 packages.modulename
 (4) Optionally rename/change to a better keyword used in this context?)

As above, I think the current method allows for this sort of thing if you're willing to manually create your own header files.

I am not. ;)
 The purpose of the module declaration is to determine the mangled name
 of symbols in that file, and import necessarily refers to file names
 rather than module names.  So do something like this:

     // src/a/b/foo.d
     module a.b;

     void doFoo() {}


     // src/a/b/bar.d
     module a.b;

     void doBar() {}


     // include/a/b.di
     module a.b;

     void doFoo();
     void doBar();

Note that I haven't tried this, but given my understanding of DMD I 
think it would work.

I tried it and it works. It required me to compile all files individually but it practically proved that the "merging package levels" is actually already working/possible! (Also seems to be trivial) However, the .di workaround, as you said, is similar to C/C++ include files usage and one of the things D targets to get rid of. Therefore I see the proposed solution ('module' to 'package') could really improve things. The last issue to check if removing the packagename != modulename definition does not create any problems in relation to this and the name mangling as noted in another reply. --- Martin Szulecki
May 11 2006