It is currently Wed Nov 20, 2019 8:08 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 13 posts ] 
Author Message
 Post subject: Allow '::' to access the global scope from within a module
PostPosted: Thu Jul 19, 2018 5:16 pm 
Offline
Addict
Addict

Joined: Sat Jun 30, 2007 8:04 pm
Posts: 3362
Modules do not inherit their parent's scope. I think that this is a GOOD thing as it ensures that modules will never have the risk of name clashes. But we still need a way to access the portions of global scope we need to prevent code duplication which can result in errors.

We can't do this:

Code:
Structure SomeStruct
EndStructure

DeclareModule SomeModule
  ; [COMPILER] Structure Not found: SomeStruct.
  Define a.SomeStruct
EndDeclareModule


We have to do this:

Code:
Structure SomeStruct
  a.i
  b.i
  c.i
EndStructure

DeclareModule SomeModule
  Structure SomeStruct
    a.i
    b.i
    c.i
  EndStructure
 
  ; [COMPILER] Structure Not found: SomeStruct.
  Define a.SomeStruct
EndDeclareModule


We CAN do this by explicitly wrapping things in another module and then accessing it by its module name:

Code:
DeclareModule Stuff_I_Need
  Structure SomeStruct
    a.i
    b.i
    c.i
  EndStructure
EndDeclareModule

Module Stuff_I_Need
EndModule

DeclareModule SomeModule
  Define a.Stuff_I_Need::SomeStruct
EndDeclareModule

Module SomeModule
EndModule


But imo, this is needlessly complex, confusing to read, and verbose.

Alternatively we could just use '::' with no prefix to denote that we want to access the global scope:

Code:
Structure SomeStruct
  a.i
  b.i
  c.i
EndStructure

DeclareModule SomeModule
  Define a.::SomeStruct
EndDeclareModule


and

Code:
Structure SomeStruct
  a.i
  b.i
EndStructure

DeclareModule OtherModule
  Structure OtherStruct Extends ::SomeStruct
    c.f
    d.f
  EndStructure
 
  Define b.OtherStruct
EndDeclareModule

Module OtherModule
EndModule


Last edited by Mistrel on Wed Jan 23, 2019 7:40 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope
PostPosted: Thu Jul 19, 2018 9:32 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Jun 28, 2003 12:01 am
Posts: 490
Another idea: completly avoid the global scope!

Code:
XIncludeFile "moduleA.pbi"
XIncludeFile "moduleB.pbi"

DeclareModule Application
   EnableExplicit
EndDeclareModule

Module Application
   Procedure Main()
      Debug "Start Application::Main()"
      ; ...
      A::Init()
      B::Init()
      ; ...
      Debug "Finish Application::Main()"
      ProcedureReturn #Null
    EndProcedure
    Main()
 EndModule


If you realy need application wide elements (structures, variables, ...) you can declare them inside the application module and use it with "Application::..." or with "Use Application" inside other modules.

_________________
Windows 10 / Windows 7
PB Last Final / Last Beta Testing


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope
PostPosted: Fri Jul 20, 2018 4:57 am 
Offline
Addict
Addict

Joined: Sat Jun 30, 2007 8:04 pm
Posts: 3362
helpy wrote:
If you realy need application wide elements (structures, variables, ...) you can declare them inside the application module and use it with "Application::..." or with "Use Application" inside other modules.


This isn't portable as it tightly couples modules to this convention.


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope
PostPosted: Fri Jul 20, 2018 5:29 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Jun 28, 2003 12:01 am
Posts: 490
Mistrel wrote:
This isn't portable as it tightly couples modules to this convention.


OK! I understand your argument.

But, I could say the same about your convention.

_________________
Windows 10 / Windows 7
PB Last Final / Last Beta Testing


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope
PostPosted: Fri Jul 20, 2018 8:10 am 
Offline
Enthusiast
Enthusiast

Joined: Mon Jun 23, 2014 1:18 pm
Posts: 150
I solved it the ugly way.

Code:
DeclareModule Test
    includefile "structureModuleDeclare.pbi"
EndDeclareModule

Module Test
    EnableExplicit
    includefile "structureModule.pbi"
EndModule


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope
PostPosted: Fri Jul 20, 2018 1:48 pm 
Offline
Administrator
Administrator

Joined: Fri May 17, 2002 4:39 pm
Posts: 13628
Location: France
The proper way to this is to use a 'Common' or 'Global' Module and use UseModule in module which needs it:

Code:
DeclareModule Stuff_I_Need
  Structure SomeStruct
    a.i
    b.i
    c.i
  EndStructure
EndDeclareModule

Module Stuff_I_Need
EndModule

DeclareModule SomeModule
  UseModule Stuff_I_Need
  Define a.SomeStruct
EndDeclareModule

Module SomeModule
EndModule


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope
PostPosted: Fri Jul 20, 2018 2:06 pm 
Offline
Enthusiast
Enthusiast

Joined: Mon Dec 21, 2015 8:12 pm
Posts: 143
How much bounty would such a feature take? :)


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope
PostPosted: Fri Jul 20, 2018 2:17 pm 
Offline
Addict
Addict

Joined: Sat Jun 30, 2007 8:04 pm
Posts: 3362
Fred wrote:
The proper way to this is to use a 'Common' or 'Global' Module and use UseModule in module which needs it


Again, this isn't portable as it tightly couples modules to this convention. It can conflict with other people's code which uses the same convention and cause problems when trying to merge code with different conventions.

I know that you were trying to be helpful citing UseModule but the whole point of my example was to demonstrate how I don't want to put what would otherwise be available in global scope into a module.

Because modules do not inherit the global scope, this would mean that literally everything everywhere would have to be contained in some module somewhere for this to work.


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope
PostPosted: Fri Jul 20, 2018 2:45 pm 
Offline
Administrator
Administrator

Joined: Fri May 17, 2002 4:39 pm
Posts: 13628
Location: France
This the whole point of module to be self contained, allowing global scope access would break this. if you plan to write your program using module, you should have everything in a module, as helpy said, it's not an issue to reuse any module you want in another. In C++ or any other OOP language you don't use the global scope anymore, you just do it all with class based coding, it's the same for modules. FYI, the IDE uses a lot of module, and it works great (we have a 'Common' module for all global items and modules which requiers it, just import it).


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope
PostPosted: Fri Jul 20, 2018 5:12 pm 
Offline
Addict
Addict

Joined: Sat Jun 30, 2007 8:04 pm
Posts: 3362
Fred wrote:
In C++ or any other OOP language you don't use the global scope anymore, you just do it all with class based coding, it's the same for modules.


In C++, scope operators which are defined by open and close braces ('{' and '}') always inherit their parent scope:

Code:
struct SomeStruct {
};

class SomeClass {
   // Inherits SomeStruct from global scope
   SomeStruct _struct;
};

namespace space {
   // Inherits SomeClass from global scope
   SomeClass _object;
}


You mention that "other OOP languages do not have this issue", which is true. But this is not a fair comparison because OOP languages have the benefit of encapsulation behind class objects and the ease of access through methods. To share anything with modules you must either use the module name everywhere or risk name clashes which result from UseModule. While class methods are accessible through their objects, we must bring all functions and other relevant definitions into the current scope before we can do anything. But because we have no automatic conflict resolution, we must use overly verbose module names or risk a compiler error.

Name clashing with Modules:

Code:
DeclareModule Module_With_Item
  ; Public
  Structure Item
  EndStructure
EndDeclareModule

Module Module_With_Item
EndModule

DeclareModule Module_Using_Item
  ; Using everything in this module that is public
  UseModule Module_With_Item
 
  ; [COMPILER ERROR] Cannot redefine when UseModule conflicts
  Structure Item
  EndStructure
EndDeclareModule

Module Module_Using_Item
EndModule


As a comparison, name clashing does not happen in OOP due to classes encapsulating all scope (pseudocode):

Code:
Class ClassA
  Structure Item
  EndStructure
EndClass

Class ClassB
  ; Structure does not conflict because ClassA.Item is still scoped even when
  ; the class is public
  obj.ClassA
 
  Structure Item
  EndStructure
 
  a.ClassA::Item ; <- ClassA scoped Item is still accessible
  b.Item ; <- ClassB scoped Item never conflicts
EndClass


PureBasic's implementation of modules is a strange amalgamation which uses strict class-like scoping without inheritance designed for OOP in a procedural language without support for submodules (modules cannot be defined inside other modules) and name conflict resolution. All of this makes modules very difficult to use and has me questioning whether they actually provide any real benefit over a prefix.

My opinion of the current implementation is that it was a decision to make modules easier to implement. For example, if modules were as they are right now but DID inherit from the global scope then you would have this immediate problem:

Code:
Structure Item
EndStructure

DeclareModule SomeModule
  ; [COMPILER ERROR] Cannot redefine inherited Item structure
  Structure Item
  EndStructure
EndDeclareModule


PureBasic does NOT allow the redefinitions like this for obvious reasons, which makes sense in a single global scope. But within modules this should be ALLOWED. But because it isn't, heavy use of modules only shifts the problem out of global scope and into module scope.

Code:
DeclareModule ModuleA
  Structure Item
  EndStructure
EndDeclareModule

DeclareModule ModuleB
  UseModule ModuleA
 
  ; [COMPILER ERROR] Cannot redefine inherited Item structure
  Structure Item
  EndStructure
EndDeclareModule


I was initially excited about modules after reading the documentation:

Quote:
Modules are an easy way to isolate code part from the main code, allowing code reuse and sharing without risk of name conflict. In some other programming languages, modules are known as 'namespaces'.


Until I discovered that, while they do isolate code, they still carry the same risk of name conflict and are nothing at all like namespaces.

The suggestion to use a "common" or "global" module is especially frightening and this is the polar opposite encapsulation by encouraging what is akin to global variables being accessed in functions to share data. Although truly a throwback to Basic, this style of coding is brain damaging. Here is an excerpt from the documentation (emphasis mine):

Quote:
To share information between modules, a common module can be created and then used in every modules which needs it. It's the common way have GLOBAL data available for ALL modules.


Code:
; The common module, which will be used by others to share data
;
DeclareModule Cars
  Global NbCars = 0
EndDeclareModule

Module Cars
EndModule

; First car module
;
DeclareModule Ferrari
EndDeclareModule

Module Ferrari
  UseModule Cars
 
  NbCars+1
EndModule

; Second car module
;
DeclareModule Porche
EndDeclareModule

Module Porche
  UseModule Cars
 
  NbCars+1
EndModule

Debug Cars::NbCars


Imo, modules were a good idea but tried to sidestep the elephant in the room: name clashes. The obvious casualty of this was the loss of global scope. To fix modules we need two things. Firstly, modules should inherit the global scope. Secondly, name clashes should be ALLOWED with definitions inside modules taking precedence.

Here is an example of how it could be implemented (this is how C++ does it with namespaces):

Code:
; Global scope Item
Structure Item
EndStructure

DeclareModule ModuleA
  ; ModuleA Item
  Structure Item
  EndStructure
EndDeclareModule

DeclareModule ModuleB
  UseModule ModuleA
 
  ; ModuleB Item
  Structure Item
  EndStructure
 
  Define a.Item ; <- ModuleB Item
  Define a.ModuleA::Item ; <- ModuleA Item (explicit because of conflict)
  Define a.::Item ; <- Global scope Item (explicit because of conflict)
EndDeclareModule


These two subtle changes will allow for cleaner, clearer, and more portable code and breathe life back into our modules.

I know this has been a long post but there were a lot of points to cover on this topic. I put a long of time, testing and research into this and hope that I've been able to present all of my arguments clearly enough for everyone to understand. Please let me know if you need anything further explained.


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope from within a modu
PostPosted: Sun Sep 29, 2019 11:24 pm 
Offline
Enthusiast
Enthusiast

Joined: Mon Nov 25, 2013 6:41 am
Posts: 794
Mistrel You are actually saying the right thing, I support you with both hands.
Code:
DeclareModule ModuleB
  UseModule ModuleA
 
  ; ModuleB Item
  Structure Item
  EndStructure

the only thing I do not think is possible to implement.
I don’t understand why Fred doesn’t want to implement this.


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope from within a modu
PostPosted: Sun Sep 29, 2019 11:47 pm 
Offline
Addict
Addict

Joined: Sat Jun 30, 2007 8:04 pm
Posts: 3362
Modifying the compiler to add new features is hard and Fred et al might not have the financial incentive to expand the language as we may want.

It's much easier to instead add additional libraries and this is probably sufficient for the majority of their users.

I have a lot of other interesting feature requests if you haven't seem them. These are my top three:

Allow structure pointers as return types
Allow interfaces as return types

This last one is subjective but it is important to me:

Allow splitting function lines before the paremeter list


Top
 Profile  
Reply with quote  
 Post subject: Re: Allow '::' to access the global scope from within a modu
PostPosted: Mon Sep 30, 2019 1:57 am 
Offline
Addict
Addict

Joined: Sat Jun 30, 2007 8:04 pm
Posts: 3362
I just discovered a new problem caused by the way modules are implemented. Despite modules being considered as self-contained and non-inheriting of the global scope, they do in fact inherit from the global scope so long as long as they have been defined in a resident file:

You can't do this because PointXY is out of scope:

Code:
Structure PointXY
EndStructure

DeclareModule Shapes
  a.PointXY
EndDeclareModule


Quote:
Structure not found: PointXY.


You also can't provide your own structure POINT as that is inherited from a resident file (Win32 API):

Code:
DeclareModule Shapes
  Structure Point
  EndStructure
EndDeclareModule


Quote:
Structure already declared: Point (in a resident file).


Unless it's something you've defined yourself. Then it works:

Code:
Structure PointXY
  a.l
  b.l
EndStructure

DeclareModule Shapes
  Structure PointXY
    x.l
    y.l
  EndStructure
EndDeclareModule

Module Shapes
EndModule

Define a.PointXY

a\a=1
a\b=2

Define b.Shapes::PointXY

b\x=1
b\y=2


This also works fine due to resident definitions being in scope:

Code:
DeclareModule Shapes
  a.POINT
  b=#PI
EndDeclareModule

Module Shapes
EndModule


So, modules don't inherit from the global scope. Except when they do. And can redefine definitions from the global scope. Except when they can't.

Fred wrote:
In C++ or any other OOP language you don't use the global scope anymore, you just do it all with class based coding, it's the same for modules.


This is another example of how it's not the same. Other languages, such as C++, inherit their parent scope while also allowing for redefinition.

Fred, please consider this feature request to bring sanity and life to PureBasic modules. They are a missed opportunity.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye