www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - is there a way to enforce module 'namespace' semantics?

reply clayasaurus <clayasaurus gmail.com> writes:
Hi,

Say I have module foo, and it has funtion bar, like this

------foo.d---------------
module foo;

void bar()
{
}
--------------------------

Now, I'm writing a library and I don't want the user of the library to 
be able to call bar by itself, like this

------main.d--------------
import foo;

bar(); // nose
--------------------------

Instead, I want to make it so the only way the user can call bar is like 
this

------main.d--------------
import foo;

foo.bar(); // yes
--------------------------

Is there a way I can enforce the functions inside of the module? Maybe 
like this?

------foo.d---------------
module foo;

enforce // enforces module 'namespace'
{
   void bar()
   {
   }
}
--------------------------

The reason I want to enforce the module 'namespace' is because I'm using 
modules as a replacement for a global class. I have multiple modules 
with similar function names, and as the library writer, I don't want my 
users to just call 'bar()', because it is not how I want the module to 
be used and the compiler will complain if they import another module 
with the same function name 'bar()'

Is there a good solution to this problem? Or should there be some way to 
enforce module 'namespace' within D?

Thanks.
  - Clay
Mar 20 2005
next sibling parent reply Chris Sauls <ibisbasenji gmail.com> writes:
clayasaurus wrote:
 Instead, I want to make it so the only way the user can call bar is like 
 this
 ------main.d--------------
 import foo;
 
 foo.bar(); // yes
 --------------------------

A darn good question: I'd very much like this myself. One possible (albeit hackish) solution I thought of off the top of my head would be to use static members of an abstract class... ie: # module foo; # # abstract class Foo { # static void bar() { } # } # module main; # import foo; # # // ... # Foo.bar(); # // ... Granted it probably provides feeding ground for cute errors from missing capitalization, but it should work. Maybe I'll test it later. -- Grant
Mar 20 2005
parent clayasaurus <clayasaurus gmail.com> writes:
Chris Sauls wrote:
 clayasaurus wrote:
 
 Instead, I want to make it so the only way the user can call bar is 
 like this
 ------main.d--------------
 import foo;

 foo.bar(); // yes
 --------------------------

A darn good question: I'd very much like this myself. One possible (albeit hackish) solution I thought of off the top of my head would be to use static members of an abstract class... ie: # module foo; # # abstract class Foo { # static void bar() { } # } # module main; # import foo; # # // ... # Foo.bar(); # // ... Granted it probably provides feeding ground for cute errors from missing capitalization, but it should work. Maybe I'll test it later. -- Grant

That may be a decent alternative, but it doesn't cut it for me, since it is using pseudo-module namespace, and you can call weird things like... foo.Foo.bar() // i think It would be simpler to just let the compiler bite the user when they try to do this ---------------------------- import foo1; // has bar() import foo2; // has bar() bar(); ---------------------------- but it would be more consistent to be able to enforce the 'namespace', so this kind of thing can never happen (it does when programmers get shortsighted/lazy) Thanks for the reply : ) - Clay
Mar 20 2005
prev sibling next sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
 The reason I want to enforce the module 'namespace' is because I'm using 
 modules as a replacement for a global class. I have multiple modules with 
 similar function names, and as the library writer, I don't want my users 
 to just call 'bar()', because it is not how I want the module to be used

why not? D is designed to be used that way. Can you give more details about the API? Personally I wouldn't fight the standard D style but one is free to make whatever API one wants, I suppose. If the standard approach results in errors or painful usage then I suggest posting examples so that Walter can try to find a nice solution.
 and the compiler will complain if they import another module with the same 
 function name 'bar()'

It should only complain when they try to use it. When that happens they will have to use the foo.bar or an alias to fix the conflict. You might be seeing import conflicts because of public imports, too. This, actually, is one reason why private imports are better than public ones because it can be nasty to track down conflicts when you nest several public imports and somewhere along the chain a conflict happens. Keeping everything private prevents that from happening. -Ben
Mar 20 2005
parent reply clayasaurus <clayasaurus gmail.com> writes:
Ben Hinkle wrote:
The reason I want to enforce the module 'namespace' is because I'm using 
modules as a replacement for a global class. I have multiple modules with 
similar function names, and as the library writer, I don't want my users 
to just call 'bar()', because it is not how I want the module to be used

why not? D is designed to be used that way. Can you give more details about the API? Personally I wouldn't fight the standard D style but one is free to make whatever API one wants, I suppose. If the standard approach results in errors or painful usage then I suggest posting examples so that Walter can try to find a nice solution.

I would rather use a 'module global' instead of a 'class global', because with classes you have to 'new' it, and you have to give it a name, which would probably be something like 'gClass'. With a 'module global', the name is the module name, and I don't have to 'new' it. These globals are ok for me, because they are there for the entire length of the program, and everything needs easy access to them. Also, with module global, there is no need for declaration, as you just use 'import module' : ) I see this as a nice solution, and easy for the user of your program to use, for instance ---------------------------------- import input; input.open() input.process() if (input.keyDown('a')) writefln("a key is down") ---------------------------------- versus ---------------------------------- import input; gInput = new Input(); gInput.open(); gInput.process() if (gInput.keyDown("a")) writefln("a key is down"); ---------------------------------- Also, I have a module named window, which holds window width, size, etc, and that has similar function names so the code is familiar. I am not asking that all D modules require this, I am just asking for a keyword (or something else?) to enforce the module namespace, or asking if someone can think of a better solution (I know I am not a master programmer) What I have, a snippet from my code, is something like this... ---- input.d -------------- module input; private { // vars } public { // funcs open() close() } --------------------------- I have a very similar ------- window.d ---------- module window; private { // vars } public { open() close() } -------------------------- Now, with my program, window and input and guarenteed to be used together, and if one calls open(); // depending on the cirsumstance, will either err or be 'ok', // but for consistency, I would rather force the code to be // input.open() or window.open(), so the programmer knows what // is happening and so, depending on what you import, you don't // all of a sudden get the compiler complaining to you Maybe I'm making a big deal out of nothing, and I'll just let an ignorant programmer write weird code that could mean different things depending on what I import.
 
 
and the compiler will complain if they import another module with the same 
function name 'bar()'

It should only complain when they try to use it. When that happens they will have to use the foo.bar or an alias to fix the conflict.

if i can choose to have the compiler complain about foo in the first place, no worries :) as they'll have to use foo.bar. also, they will not want to use an alias, because there is no better name they can alias too :)
 
 You might be seeing import conflicts because of public imports, too. This, 
 actually, is one reason why private imports are better than public ones 
 because it can be nasty to track down conflicts when you nest several public 
 imports and somewhere along the chain a conflict happens. Keeping everything 
 private prevents that from happening.

It might be nice for D to force either 'public' or 'private' on all things within the module, and not default everything to 'public' or 'priavte' I know, at first, I didn't understand that D defaulted all module access to public. And, I don't think it hurts productivity to force either public or private, rather it makes the programmer think about what they really want to be shared within a module, potentially avoiding hard to track down future module conflicts within large programs. Anyway, what it boils down to for me is that if i have module module foo; // has bar() in it module dance; // has bar() in it bar(); // the compiler will complain, no? Bar, is a public function, I want it to be public, I need it to be public. I know what I can hide and what I can't. :) I just think it would be nice if I could make the compiler complain in the first place, so my library can not be abused.
 
 -Ben 
 
 

Mar 20 2005
parent reply Lukas Pinkowski <Lukas.Pinkowski web.de> writes:
clayasaurus wrote:

 Ben Hinkle wrote:
The reason I want to enforce the module 'namespace' is because I'm using
modules as a replacement for a global class. I have multiple modules with
similar function names, and as the library writer, I don't want my users
to just call 'bar()', because it is not how I want the module to be used

why not? D is designed to be used that way. Can you give more details about the API? Personally I wouldn't fight the standard D style but one is free to make whatever API one wants, I suppose. If the standard approach results in errors or painful usage then I suggest posting examples so that Walter can try to find a nice solution.

I would rather use a 'module global' instead of a 'class global', because with classes you have to 'new' it, and you have to give it a name, which would probably be something like 'gClass'. With a 'module global', the name is the module name, and I don't have to 'new' it.

I use classes with static methods and properties, thus having something like a namespace. You don't have to 'new' a class to use its static methods and members and you are forced to use MyClass.method() instead of just method() like in modules. ie. module input; class Input { static { void open() { bla } void process() { bla } ... } } and import input; Input.open(); Input.process(); ...
Mar 20 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
 I use classes with static methods and properties, thus having something 
 like
 a namespace. You don't have to 'new' a class to use its static methods and
 members and you are forced to use MyClass.method() instead of just 
 method()
 like in modules.

 ie.

 module input;
 class Input
 {
  static
  {
    void open() { bla }
    void process() { bla }
    ...
  }
 }

 and

 import input;

 Input.open();
 Input.process();

 ...

Maybe it's just me but I don't want to see this become common in D. The whole point of the module rules is to free users from having to type Input. or whatever. Please don't force me as a user of your library to work in Java style where dummy classes wrap top-level functions. If you (meaning a library author) wants to always include the module name in your code because you think it looks nice then feel free to do that (it is legal D so it isn't a problem). But please let's keep D libraries free from the hacks that other languages need. The module rules in D are flexible enough to keep everyone happy. If they aren't then we need to alert Walter so that he can fix it up.
Mar 20 2005
parent reply clayasaurus <clayasaurus gmail.com> writes:
Ben Hinkle wrote:
I use classes with static methods and properties, thus having something 
like
a namespace. You don't have to 'new' a class to use its static methods and
members and you are forced to use MyClass.method() instead of just 
method()
like in modules.

ie.

module input;
class Input
{
 static
 {
   void open() { bla }
   void process() { bla }
   ...
 }
}

and

import input;

Input.open();
Input.process();

...

Maybe it's just me but I don't want to see this become common in D. The whole point of the module rules is to free users from having to type Input. or whatever.

When you have two modules with the same functions, you are forced to type input anyway, the compiler will complain. In my lib, you are guarenteed to have two modules with the same function names, out of design. What happens when it goes wrong is that it you get a weird error message, like "foo.d(3): function foo.fooo conflicts with bar.fooo at bar.d(3)," that doesn't give you the name of the source file where the actual conflict occurs (in this case main.d), and it is a bit hard to track down in a large program. I thought it would be better to enforce module namespace so these errors do not happen, and if you forget to do it then the compiler can tell you the line of code it goes wrong on.
 Please don't force me as a user of your library to work in Java 
 style where dummy classes wrap top-level functions. If you (meaning a 
 library author) wants to always include the module name in your code because 
 you think it looks nice then feel free to do that (it is legal D so it isn't 
 a problem). But please let's keep D libraries free from the hacks that other 
 languages need. The module rules in D are flexible enough to keep everyone 
 happy. If they aren't then we need to alert Walter so that he can fix it up. 
 

I've decided i'm not going to use static classes or whatever (though neat trick!) I'll just let the compiler bite when it feels it is time :-) And then they can have fun tracking it down, without DMD telling you the line or source where the conflict occurs. fun.
Mar 20 2005
next sibling parent "Carlos Santander B." <csantander619 gmail.com> writes:
clayasaurus wrote:
 
 I've decided i'm not going to use static classes or whatever (though 
 neat trick!)
 
 I'll just let the compiler bite when it feels it is time :-) And then 
 they can have fun tracking it down, without DMD telling you the line or 
 source where the conflict occurs. fun.
 
 

I'm with Ben here. What if in one of your modules you forget your proposed "enforce" attribute? module a; enforce: void foo() {} module b; //oops, forgot enforce void foo() {} module usercode; void bar() { foo(); // user made a mistake: he meant a.foo } The compiler would not complain about it and the user would get a wrong result. Again, I also prefer the flexibility that D gives right now. _______________________ Carlos Santander Bernal
Mar 20 2005
prev sibling parent reply J C Calvarese <jcc7 cox.net> writes:
clayasaurus wrote:
...

 When you have two modules with the same functions, you are forced to 
 type input anyway, the compiler will complain.
 
 In my lib, you are guarenteed to have two modules with the same function 
 names, out of design.
 
 What happens when it goes wrong is that it you get a weird error 
 message, like "foo.d(3): function foo.fooo conflicts with bar.fooo at 
 bar.d(3)," that doesn't give you the name of the source file where the 
 actual conflict occurs (in this case main.d), and it is a bit hard to 
 track down in a large program.

I think this part of the issue can best be solved by a better error message. Maybe if we mention these substandard error messages enough times, Walter will have a chance to fix them. ;) -- Justin (a/k/a jcc7) http://jcc_7.tripod.com/d/
Mar 20 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Sun, 20 Mar 2005 21:48:17 -0600, J C Calvarese wrote:

 clayasaurus wrote:
 ...
 
 When you have two modules with the same functions, you are forced to 
 type input anyway, the compiler will complain.
 
 In my lib, you are guarenteed to have two modules with the same function 
 names, out of design.
 
 What happens when it goes wrong is that it you get a weird error 
 message, like "foo.d(3): function foo.fooo conflicts with bar.fooo at 
 bar.d(3)," that doesn't give you the name of the source file where the 
 actual conflict occurs (in this case main.d), and it is a bit hard to 
 track down in a large program.

I think this part of the issue can best be solved by a better error message. Maybe if we mention these substandard error messages enough times, Walter will have a chance to fix them. ;)

I suspect that you are very correct here. In general, I think that Walter needs to make a determined effort to systematically go through the compiler and standardize all the error messages. They should at the very least identify the file name and line number that *triggered* the error, and the text of the message needs to be in plain language rather than compiler-speak (i.e. Minimize the computer science jargon). -- Derek Melbourne, Australia 21/03/2005 2:52:15 PM
Mar 20 2005
parent reply J C Calvarese <jcc7 cox.net> writes:
Derek Parnell wrote:
 On Sun, 20 Mar 2005 21:48:17 -0600, J C Calvarese wrote:

What happens when it goes wrong is that it you get a weird error 
message, like "foo.d(3): function foo.fooo conflicts with bar.fooo at 
bar.d(3)," that doesn't give you the name of the source file where the 
actual conflict occurs (in this case main.d), and it is a bit hard to 
track down in a large program.

I think this part of the issue can best be solved by a better error message. Maybe if we mention these substandard error messages enough times, Walter will have a chance to fix them. ;)

I suspect that you are very correct here. In general, I think that Walter needs to make a determined effort to systematically go through the compiler and standardize all the error messages. They should at the very least identify the file name and line number that *triggered* the error, and the text of the message needs to be in plain language rather than compiler-speak (i.e. Minimize the computer science jargon).

Well, there always going to have to be some computer science jargon, but the message should at least provide all of the relevant line numbers. And I think Walter is already responsive to these criticisms, one man can only find and fix them so fast. I wonder how much we could help by pointing him to a particular string in the front-end. Hmmm... -- Justin (a/k/a jcc7) http://jcc_7.tripod.com/d/
Mar 20 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Sun, 20 Mar 2005 22:21:32 -0600, J C Calvarese <jcc7 cox.net> wrote:
 Derek Parnell wrote:
 On Sun, 20 Mar 2005 21:48:17 -0600, J C Calvarese wrote:

 What happens when it goes wrong is that it you get a weird error  
 message, like "foo.d(3): function foo.fooo conflicts with bar.fooo at  
 bar.d(3)," that doesn't give you the name of the source file where  
 the actual conflict occurs (in this case main.d), and it is a bit  
 hard to track down in a large program.

I think this part of the issue can best be solved by a better error message. Maybe if we mention these substandard error messages enough times, Walter will have a chance to fix them. ;)

Walter needs to make a determined effort to systematically go through the compiler and standardize all the error messages. They should at the very least identify the file name and line number that *triggered* the error, and the text of the message needs to be in plain language rather than compiler-speak (i.e. Minimize the computer science jargon).

Well, there always going to have to be some computer science jargon, but the message should at least provide all of the relevant line numbers. And I think Walter is already responsive to these criticisms, one man can only find and fix them so fast. I wonder how much we could help by pointing him to a particular string in the front-end. Hmmm...

I had a very brief look at the front end code (so I may be way off base here) but I noticed the error function simply gets passed a string, which it then prints. What if Walter changes that to take a file, line and error. The function could then print in a set format, the calling code would all error highlighting all the calls which now require file/line information. Regan
Mar 20 2005
prev sibling parent Ilya Minkov <minkov cs.tum.edu> writes:
I think you may have something like:

implementation_module.d - all your real stuff is here,
including definition of functionCall().

module.d:
// Proxy
struct module{
	import implementation_module;
}
// end of module.d

test.d:
import module;

void main(){
	// this should work:
	module.functionCall();
	// this must fail:
	//~ functionCall();
}
// end of module.d

However, if you really have collision on function names, it might be a 
hint that you might want to bring some class encapsulation into the 
game, or solve the issue otherwise. You should never give functions the 
same name, unless they also do exactly the same - perhaps, on different 
types. However, if they do the same, you have 2 possibilities: either 
drop all functions into the same namespace, or you can find a place in a 
class hierarchy, making full-scale methods out of them.

To drop all the functions into the same namespace, you need not define 
them in the same module. Instead, say ambiguousFunction() is defined in 
module1, module2 and module3, using different types as argument. Then in 
  a new module you may do:

module common;

private import module1, module2, module3;

alias module1.ambiguousFunction ambiguousFunction;
alias module2.ambiguousFunction ambiguousFunction;
alias module3.ambiguousFunction ambiguousFunction;

Now when you import them all through module "common" they will obey to 
type overloading correctly.

-eye
Mar 21 2005