www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Suggestion: module opcall

reply bobef <ads asd.asd> writes:
Hello all,

I want to suggest adding module opCall to D (to D1 as well please :). Please
excuse me if has been suggested before. Something like this:

module mymodule.trace;

static char[] opCall() {
  return  "whatever";
}

module mymodule.main;

void main() {
  mymodule.trace();
}

The need for this is because often a module happens to be named as the
functionality it contains and you have to write the stuff two times. For
example to stdout something with Tango one needs to
tango.io.Stdout.Stdout("whatever"); It would be much nicer to just write
tango.io.Stdout("whatever"); Other cases don't come to mind at the moment, but
I have thought about this many times in my work...

Regards,
bobef
Jan 08 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
bobef Wrote:
 The need for this is because often a module happens to be named as the
functionality it contains and you have to write the stuff two times.<
A design bug in the D1 module system is that when you import foo normally you import in the namespace both the module name and the names it contains. So if you have foo inside foo you are in troubles. I'm waiting such design errors to be fixed still. Anyway, you can solve your problem like this: from foo import foo; now you don't need to call foo two names to use it. So for *this purpose* I think your proposal is bad (it may be good for other purposes). Bye, bearophile
Jan 08 2009
parent reply "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Jan 9, 2009 at 2:33 AM, bearophile <bearophileHUGS lycos.com> wrote:
 bobef Wrote:
 The need for this is because often a module happens to be named as the
functionality it contains and you have to write the stuff two times.<
A design bug in the D1 module system is that when you import foo normally you import in the namespace both the module name and the names it contains. So if you have foo inside foo you are in troubles. I'm waiting such design errors to be fixed still.
I think this problem you refer to only applies to modules without package names. I.e. "module Foo" containing "class Foo". Things seem to work ok if you have "module x.Foo" with "class Foo" inside. So you are saying you want this to be an error? import std.string; void foo() { std.string.format("hi"); // error no such symbol "std.string" format("hi"); // ok }
 Anyway, you can solve your problem like this:
 from foo import foo;
He can solve his problem by using Python with semicolons? I don't think that really solves it though. The original request used the full package name. I'm a big fan of static imports, but I have to agree that I just can't bring myself to use static imports when the names are things like mylibs.util.Array.Array. It just looks stupid. But when you have a module that basically implements only one class what *should* you call that module? There's no good way to do it, except to try to organize your library like Phobos and put lots of stuff in every module. So I think there is a need for a way to have eponymous one-class modules. The D package stuff seems to have been inspired largely by Java's, but the big difference is that in java it's always one-module<=>one-class so they don't have this problem. But I don't think module opCall is the right solution. It looks ok for the Stdout case because typical usage of Stdout is Stdout(). But what about .flush? For that you'd still be doing tango.io.Stdout.Stdout.flush. If anything it's more like a module opDot that you want. I don't think that's really the right way to go either, though. I think the situation is more like the template stuff. template Foo(T) { void Foo(T x) { } } Foo(3); /// Foo.Foo not needed Compare with: static import Foo; auto x = new Foo; // Foo.Foo should not be needed if class Foo is the only thing inside Foo. On the other hand, I'd really like to see the template thing fixed so there's some way to put private stuff inside there too. Similarly it'd be nice if it would work for modules as long as class Foo was the only non-public thing. I think both cases might be made cleaner by some judicious re-use of the 'this' keyword. Such as: template AReallyLongTemplateNameIDontWannaTypeTwice(T) { void this(T x) { } } and with the modules it would be: module pkg.Foo; class this { // Hi I'm the single representative class for Foo, implicitly accessible via the module name pkg.Foo. } I love how I don't have to change all the constructor names in D whenever I change a class name. Extending that DRY goodness to templates (and maybe modules too) would be nice I think. --bb
Jan 08 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Bill Baxter:

I think this problem you refer to only applies to modules without package
names.  I.e. "module Foo" containing "class Foo".  Things seem to work ok if
you have "module x.Foo" with "class Foo" inside.<
Right. But why settle with a half-backed module system when there are more logic ways to design it? :-)
 So you are saying you want this to be an error?
 
 import std.string;
 void foo() {
     std.string.format("hi");  // error no such symbol "std.string"
     format("hi");   // ok
 }
The following examples show what I mean: import std.string; void foo() { std.string.format("hi"); // OK, "std.string" name exists in the current scope. format("hi"); // Error, "format" name is absent. } import std.string: format; void foo() { std.string.format("hi"); // Error, "std" name is absent. format("hi"); // OK. } import std.string: *; void foo() { std.string.format("hi"); // Error, "std" name is absent. format("hi"); // OK, all names inside "std.string" are now present in the current scope. } import std.string; import std.string: format; void foo() { std.string.format("hi"); // OK. format("hi"); // OK. } This doesn't solve all problems, but it's a good step toward improving the situation.
auto x = new Foo;  // Foo.Foo should not be needed if class Foo is the only
thing inside Foo.<
That's a special casing, it may look handy, but it may also lead to troubles later. So I think it's better to keep things tidy, and avoid that. D allows enough things (renamed imports, alias, and selective imports) to solve such problems already.
 template AReallyLongTemplateNameIDontWannaTypeTwice(T) {
      void this(T x) { }
 }
You can write that in D1 as: void aReallyLongTemplateNameIDontWannaTypeTwice(T)(T x) { }
I love how I don't have to change all the constructor names in D whenever I
change a class name.<
I agree, but for example when you define a opCmp of a struct you have to do: struct Foo { int x; int opCmp(Foo other) { ... As you can see the name Foo is repeated two times, and I don't like that much (I don't use an IDE able to refractor names). In D1 I sometimes solve that small problem like this: struct Foo { int x; int opCmp(typeof(*this) other) { ... Or like this: struct Foo { int x; alias typeof(*this) TyThis; int opCmp(TyThis other) { ... Bye, bearophile
Jan 08 2009
parent reply "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Jan 9, 2009 at 10:23 AM, bearophile <bearophileHUGS lycos.com> wrote:
 Bill Baxter:

I think this problem you refer to only applies to modules without package
names.  I.e. "module Foo" containing "class Foo".  Things seem to work ok if
you have "module x.Foo" with "class Foo" inside.<
Right. But why settle with a half-backed module system when there are more logic ways to design it? :-)
 So you are saying you want this to be an error?

 import std.string;
 void foo() {
     std.string.format("hi");  // error no such symbol "std.string"
     format("hi");   // ok
 }
The following examples show what I mean: import std.string; void foo() { std.string.format("hi"); // OK, "std.string" name exists in the current scope. format("hi"); // Error, "format" name is absent. }
Ok. You mean like Python. I guess people here have bullied you into stop using that phrase. :-) That would be fine by me. I'm also a big supporter of static import by default. But I think it still doesn't solve the Stdout.Stdout annoyance does it?
auto x = new Foo;  // Foo.Foo should not be needed if class Foo is the only
thing inside Foo.<
That's a special casing, it may look handy, but it may also lead to troubles later. So I think it's better to keep things tidy, and avoid that. D allows enough things (renamed imports, alias, and selective imports) to solve such problems already.
If you think so, then you should argue for removal of the special case stuff for templates too. On the other hand, if it worked for modules templates and classes, then would it be all that much of a special case?
 template AReallyLongTemplateNameIDontWannaTypeTwice(T) {
      void this(T x) { }
 }
You can write that in D1 as: void aReallyLongTemplateNameIDontWannaTypeTwice(T)(T x) { }
Ok, bad example. Try that for a template that defines a constant or an alias. template AReallyLongTemplateNameIDontWannaTypeTwice(T) { alias T[] ReallyLongTemplateNameIDontWannaTypeTwice; } --bb
Jan 08 2009
parent "Nick Sabalausky" <a a.a> writes:
----- Original Message ----- 
From: "Bill Baxter" <wbaxter gmail.com>
Newsgroups: digitalmars.D
To: "digitalmars.D" <digitalmars-d puremagic.com>
Sent: Thursday, January 08, 2009 8:49 PM
Subject: Re: Suggestion: module opcall


 On Fri, Jan 9, 2009 at 10:23 AM, bearophile <bearophileHUGS lycos.com>
 wrote:
 Bill Baxter:

I think this problem you refer to only applies to modules without package
names.  I.e. "module Foo" containing "class Foo".  Things seem to work ok
if you have "module x.Foo" with "class Foo" inside.<
Right. But why settle with a half-backed module system when there are more logic ways to design it? :-)
 So you are saying you want this to be an error?

 import std.string;
 void foo() {
     std.string.format("hi");  // error no such symbol "std.string"
     format("hi");   // ok
 }
The following examples show what I mean: import std.string; void foo() { std.string.format("hi"); // OK, "std.string" name exists in the current scope. format("hi"); // Error, "format" name is absent. }
Ok. You mean like Python. I guess people here have bullied you into stop using that phrase. :-)
My apologies for that ;-)
 That would be fine by me.  I'm also a big supporter of static import by
 default.

 But I think it still doesn't solve the Stdout.Stdout annoyance does it?


auto x = new Foo;  // Foo.Foo should not be needed if class Foo is the
only thing inside Foo.<
That's a special casing, it may look handy, but it may also lead to troubles later. So I think it's better to keep things tidy, and avoid that. D allows enough things (renamed imports, alias, and selective imports) to solve such problems already.
If you think so, then you should argue for removal of the special case stuff for templates too. On the other hand, if it worked for modules templates and classes, then would it be all that much of a special case?
 template AReallyLongTemplateNameIDontWannaTypeTwice(T) {
      void this(T x) { }
 }
You can write that in D1 as: void aReallyLongTemplateNameIDontWannaTypeTwice(T)(T x) { }
Ok, bad example. Try that for a template that defines a constant or an alias. template AReallyLongTemplateNameIDontWannaTypeTwice(T) { alias T[] ReallyLongTemplateNameIDontWannaTypeTwice; }
I was just thinking earlier, it would be nice if could handle const templates just like we do class templates and function templates: --------------- // Before: template SomeCodeToMixin(alias name) { const char[] SomeCodeToMixin = "int "~name~";"; } // After: const char[] SomeCodeToMixin(alias name) = "int "~name~";"; --------------- Nice as that would be, it unfortunately still doesn't solve this (which I do a lot): --------------- template SomeCodeToMixin(alias a) { const char[] SomeCodeToMixin = "int "~a~";"; pragma(msg, "SomeCodeToMixin: "~SomeCodeToMixin); } --------------- For that (...deja vu?), I'd like to have: --------------- template SomeCodeToMixin(alias a) { const char[] this = "int "~a~";"; pragma(msg, this.nameof~": "~this); } --------------- Ditto on how good D's naming is for constructors/destructors. That was one of the early things that really impressed me. (I may have double-posted, sorry about that.)
Jan 08 2009