Namespace #522

Open
vicnet opened this Issue Oct 30, 2013 · 9 comments

Comments

Projects
None yet
5 participants
@vicnet
Contributor

vicnet commented Oct 30, 2013

I have start coding namespaces.
Actually, I (successfully) use module as namespace and just allow namespace variables using.

Here is the design I try:

  • parser.y no change in expression, use Expression with 'L' type (lookup)
  • expr.cc: in 'L' evaluation, find variable inside a double array [ [ 'name', Value], ... ] that represents the namespace dictionary, and return the correspondent Value
  • context.cc: virtualize lookup_variable (should be rename as lookup_name or something else)
  • modulecontext.cc: inherit from lookup_variable and search for module name before variable. If found call evaluate_module for the found module
  • module: add evaluate (like function) that gather assignments and return dictionary value (array of array with [name,value])

This allows things like:

module m() { t=5; }
mt = m.t;
echo(m.t); // outputs 5
echo(m); // ouputs [['t',5]]

To analyze:

  • 'namespace' keyword ?
  • real dictionary Value type ?

To do:

  • module instantiation from namespace
  • library namespace management (embedded no-namespace lib in namespace, and rename or remove (embed in global namespace) library namespace)

What do you think ?
Is the design correct ?


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@GilesBathgate

This comment has been minimized.

Show comment
Hide comment
@GilesBathgate

GilesBathgate Oct 30, 2013

Contributor

Namespace might not be the best term to describe what you mean here. I think what you are talking about is module 'member variables', this of course does infer that the module will have a namespace, and to access a module's member variable you need to qualify its namespace. On the more general topic of namespaces, I partially implemented an idea in RapCAD to get around conflicts in imports. (This is what I generally think of when I hear the term namespace). The idea is that you can import a module and declare its namespace e.g:

import <box.scad> as mynamespace;

module box(){...}

box();      //instantiates this modules box
mynamespace::box();   //instantiates the imported modules box

This gets around conflicts when the module you import has modules that would conflict with modules in your own script.

The syntax for namespace prefixes in my implementation was :: I found that the grammar got too ambiguous when I started trying to overload .. i.e. mynamespace.box() might 'look' nicer but I think its going to be tricky.

Contributor

GilesBathgate commented Oct 30, 2013

Namespace might not be the best term to describe what you mean here. I think what you are talking about is module 'member variables', this of course does infer that the module will have a namespace, and to access a module's member variable you need to qualify its namespace. On the more general topic of namespaces, I partially implemented an idea in RapCAD to get around conflicts in imports. (This is what I generally think of when I hear the term namespace). The idea is that you can import a module and declare its namespace e.g:

import <box.scad> as mynamespace;

module box(){...}

box();      //instantiates this modules box
mynamespace::box();   //instantiates the imported modules box

This gets around conflicts when the module you import has modules that would conflict with modules in your own script.

The syntax for namespace prefixes in my implementation was :: I found that the grammar got too ambiguous when I started trying to overload .. i.e. mynamespace.box() might 'look' nicer but I think its going to be tricky.

@vicnet

This comment has been minimized.

Show comment
Hide comment
@vicnet

vicnet Oct 30, 2013

Contributor

No, my aim is to develop a real namespace for exactly the same reason as you: avoid conflict between libraries and code.
I use module as a namespace to test my idea, but code could be transferred in real namespace keyword.
I want also to be able to call module/function inside a namespace.
I choose dot symbol because it is nicer. But you are right, it's tricky ;-)

Contributor

vicnet commented Oct 30, 2013

No, my aim is to develop a real namespace for exactly the same reason as you: avoid conflict between libraries and code.
I use module as a namespace to test my idea, but code could be transferred in real namespace keyword.
I want also to be able to call module/function inside a namespace.
I choose dot symbol because it is nicer. But you are right, it's tricky ;-)

@nophead

This comment has been minimized.

Show comment
Hide comment
@nophead

nophead Oct 30, 2013

Contributor

What happens if you do

m.t = 6;

Does it follow the normal OpenScad rule that the last assignment to a variable is the one used throughout the script?

Contributor

nophead commented Oct 30, 2013

What happens if you do

m.t = 6;

Does it follow the normal OpenScad rule that the last assignment to a variable is the one used throughout the script?

@GilesBathgate

This comment has been minimized.

Show comment
Hide comment
@GilesBathgate

GilesBathgate Oct 30, 2013

Contributor

Most of my inspiration comes from how its implemented here: http://dlang.org/module.html

Confusingly when we refer to 'modules' we mean a different thing to what they mean, their module is what we might call a script or file. Interestingly they have a scheme such that thier 'modules' have a one-to-one correspondence with source files. The module name is the file name with the path and extension stripped off. You can however still override the module name with (in thier case a module declaration) in our case a single namespace declaration per file i.e:

box.scad:

namespace giles;

module box(){...}

Or you could implement it with multiple namespaces per file as per c# and similar languages:

complex.scad

namespace giles {
 namespace innergiles { 
    module foo(){...}
 }
}

namespace vicnet {
}

As you can see the later could get very over-complicated.

Contributor

GilesBathgate commented Oct 30, 2013

Most of my inspiration comes from how its implemented here: http://dlang.org/module.html

Confusingly when we refer to 'modules' we mean a different thing to what they mean, their module is what we might call a script or file. Interestingly they have a scheme such that thier 'modules' have a one-to-one correspondence with source files. The module name is the file name with the path and extension stripped off. You can however still override the module name with (in thier case a module declaration) in our case a single namespace declaration per file i.e:

box.scad:

namespace giles;

module box(){...}

Or you could implement it with multiple namespaces per file as per c# and similar languages:

complex.scad

namespace giles {
 namespace innergiles { 
    module foo(){...}
 }
}

namespace vicnet {
}

As you can see the later could get very over-complicated.

@kintel

This comment has been minimized.

Show comment
Hide comment
@kintel

kintel Oct 30, 2013

Member

I think this will get confusing fast.
Some questions to keep in mind:

  • What is the difference between "module variables" and "module instance variables"? Variables are just expressions which can depend on parameters sent to a module during instantiation. How do we know when the value is valid without having an instance?
  • When you do use <somefile.scad>, this actually creates an anonymous module. To get access to top-level variables in such files, it would be interesting to do smth. similar to what Giles do in RapCAD. Perhaps these concepts should be better separated? Alternatively, look at e.g. the JavaScript object model and make them similar to functions in terms of function variables vs. instance variables as well as anonymous vs. named functions.
  • The existing way of sending parameters on the cmd-line is very confusing. We need to be backwards compatible in some way, but I'm not opposed to changing the normal way of doing this if we find a better design.
  • Assignments to module variables sounds scary, but it might make sense to just be flexible and allow it. The problem is (again) that OpenSCAD code isn't evaluated sequentially. See previous item; perhaps we should enforce more sequential behaviour in the future to make things less confusing. Long term issue though…

As a start, I think I need to see some example use-cases of when this functionality would make sense to try to figure out what this would mean to actual users. I'm sure the mailing list would provide a bunch of opinions on this.

Member

kintel commented Oct 30, 2013

I think this will get confusing fast.
Some questions to keep in mind:

  • What is the difference between "module variables" and "module instance variables"? Variables are just expressions which can depend on parameters sent to a module during instantiation. How do we know when the value is valid without having an instance?
  • When you do use <somefile.scad>, this actually creates an anonymous module. To get access to top-level variables in such files, it would be interesting to do smth. similar to what Giles do in RapCAD. Perhaps these concepts should be better separated? Alternatively, look at e.g. the JavaScript object model and make them similar to functions in terms of function variables vs. instance variables as well as anonymous vs. named functions.
  • The existing way of sending parameters on the cmd-line is very confusing. We need to be backwards compatible in some way, but I'm not opposed to changing the normal way of doing this if we find a better design.
  • Assignments to module variables sounds scary, but it might make sense to just be flexible and allow it. The problem is (again) that OpenSCAD code isn't evaluated sequentially. See previous item; perhaps we should enforce more sequential behaviour in the future to make things less confusing. Long term issue though…

As a start, I think I need to see some example use-cases of when this functionality would make sense to try to figure out what this would mean to actual users. I'm sure the mailing list would provide a bunch of opinions on this.

@vicnet

This comment has been minimized.

Show comment
Hide comment
@vicnet

vicnet Oct 31, 2013

Contributor

@nophead m.t = 6;: don't implement it yet, so don't think about this case.

module m() { t=5; echo(t); }
m.t=1; // value is changed in m, like affectation on variable from include file
m(); // should outputs 1

@GilesBathgate right, I start on second example way, 'a la' C++ but I could restrict to dir/file as you said if too complex (or too involved problems)

@kintel

  1. module m(u) { t=u; } echo(m.t); } outputs undef
  2. Right, I use function-variable in my lib to export variable even with 'use' keyword...
  3. on cmd-line, I don't see the relationship with namespace
  4. my aim is to avoid collision between libs, so assignment should be allowed as current assignment in lib without namespace

As I said, I re-use module to avoid introduction of new keyword but after reading this thread, I think it is too confusing.
As I just want to protect lib collisions, I think I will reduce, on a first time, my objective to Giles idea (file/dir as namespace).
What I implement is like an access to class variables but the class variable concept does not exists in scad language (yet) and it is very far from my initial need :-)

Contributor

vicnet commented Oct 31, 2013

@nophead m.t = 6;: don't implement it yet, so don't think about this case.

module m() { t=5; echo(t); }
m.t=1; // value is changed in m, like affectation on variable from include file
m(); // should outputs 1

@GilesBathgate right, I start on second example way, 'a la' C++ but I could restrict to dir/file as you said if too complex (or too involved problems)

@kintel

  1. module m(u) { t=u; } echo(m.t); } outputs undef
  2. Right, I use function-variable in my lib to export variable even with 'use' keyword...
  3. on cmd-line, I don't see the relationship with namespace
  4. my aim is to avoid collision between libs, so assignment should be allowed as current assignment in lib without namespace

As I said, I re-use module to avoid introduction of new keyword but after reading this thread, I think it is too confusing.
As I just want to protect lib collisions, I think I will reduce, on a first time, my objective to Giles idea (file/dir as namespace).
What I implement is like an access to class variables but the class variable concept does not exists in scad language (yet) and it is very far from my initial need :-)

@t-paul

This comment has been minimized.

Show comment
Hide comment
@t-paul

t-paul Nov 4, 2013

Member

As namespaces are quite important for libraries, also the concept of a version number for a library object should be considered.

With that another interesting effect of the way OpenSCAD works comes into play. In most languages, it's not possible to have multiple versions of the same object in a single program. But OpenSCAD does not "run" or "link" the libraries. They are only used to instantiate the objects described in the library as source code. So I think it would be possible the use 2 libraries A and B that depend on different version of C, e.g.:

  • main
    • libA v1.0
      • libC v1.0
    • libB v1.2
      • libC v1.1

But to make this happen, the scoping of thinks would need to be relative to the parent object instead of all included objects ending up in a flat namespace structure.

Member

t-paul commented Nov 4, 2013

As namespaces are quite important for libraries, also the concept of a version number for a library object should be considered.

With that another interesting effect of the way OpenSCAD works comes into play. In most languages, it's not possible to have multiple versions of the same object in a single program. But OpenSCAD does not "run" or "link" the libraries. They are only used to instantiate the objects described in the library as source code. So I think it would be possible the use 2 libraries A and B that depend on different version of C, e.g.:

  • main
    • libA v1.0
      • libC v1.0
    • libB v1.2
      • libC v1.1

But to make this happen, the scoping of thinks would need to be relative to the parent object instead of all included objects ending up in a flat namespace structure.

@GilesBathgate

This comment has been minimized.

Show comment
Hide comment
@GilesBathgate

GilesBathgate Nov 4, 2013

Contributor

So what you are suggesting is that you might need nested namespaces, even without the suggested nested namespace structure (a la c#), to handle nesting with respect to file structure.

that way you could do

libA::libC::mouse();

LibB::LibC::mouse();

and it would invoke the correct versions of mouse() accordingly?

Contributor

GilesBathgate commented Nov 4, 2013

So what you are suggesting is that you might need nested namespaces, even without the suggested nested namespace structure (a la c#), to handle nesting with respect to file structure.

that way you could do

libA::libC::mouse();

LibB::LibC::mouse();

and it would invoke the correct versions of mouse() accordingly?

@kintel

This comment has been minimized.

Show comment
Hide comment
@kintel

kintel Nov 5, 2013

Member

..or do what npm does for node.js.

Someone started on it, but discovered that it needs more thought.

Member

kintel commented Nov 5, 2013

..or do what npm does for node.js.

Someone started on it, but discovered that it needs more thought.

@FluxIX FluxIX referenced this issue Jul 9, 2015

Closed

htho/scadlib #1381

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment