Re: Euphoria vs. other programming languages

new topic     » goto parent     » topic index » view thread      » older message » newer message
CChris said...

Another of your lies, Critic is right someimes.

CChris said...

I did, but ayatollah Matt & Jeremy ...

Christian,
how is inflamatory language going to help you or anyone else here?

This discussion about include file philosophy comes down to a difference of opinion. You have a specific opinion about what constitutes good programming practice and the current development team has a different opinion. As you well know, before you left the team, discussions amongst us all went on for what seemed like months about this issue. A number of ideas were tried out and what we have now is, IMO, the best outcome of all those discussions and experiments. Sure, I still think we could have done it a bit differently, but not all my suggestions were endorsed by the group as a whole. I got over it.

The language still has global so you are free to continue using your coding style in your libraries. And in just the same way, the development team has standardized on an include file coding style which has been demonstrated in the new standard library. No one is trying to force you to use a particular coding style in your own code.

My take on how we got to the new position is based on what problems we were trying to solve. They included ...

  • How do we avoid name clashes with symbols that are exposed from a module (file)?
  • How do we help code readers understand file inter-dependancies?
  • How do we enable coders to group together related routines?

In v3 Euphoria, there is only one way to expose a symbol - use the global scope attribute. This meant that the probability of clashes between independantly written libraries is high. Further more, in some cases (include topologies), the only way to resolve a clash was to edit the source code of a third-party library. This 'resolution' could break at any time whenever a new release of that edited library was made, which of course was out of one's control.

Because the global scope is pervasive, one can include a file, say "A.E" that can include any number of other files, which in turn can include any number of still further files, etc, etc, etc... And a global symbol at the deepest nesting level can still be used in your application. On the surface, this seems like a handy time saver. You are not obliged to know in which particular file that symbol has been declared in. In fact, you'd probably have to use a 'grep' like tool to find it. This technique also means that you are not necessarily aware of your application's dependancy on the file that actually declares that global symbol.

In v4, we decided to make a simple rule to help us be aware of which files a given file was dependant on: If a file needs to use a symbol that has been declared in a standard library file, then it must explicitly include that standard library file.

To enable this rule to work, we came up with the public scope attribute. This is used instead of global to expose a symbol. The difference is that is only exposes the symbol to files that explicitly include it and no further up the include tree. This means that if "A" includes "B", and "B" includes "C", then "A" cannot see the public symbols declared inside "C". Of course, "A" can see "B"'s public symbols and "B" can see "C"'s public symbols.

This however gave as a new situation. When a library is huge, it is often broken into smaller sub-library files for maintenance/management reasons. Conceptually though, these sub-files are still part of a single library. It can be thought of as a multi-file library. But if an application includes the top-level library file (eg. win32lib) and that library file actually includes sub-library files in which public symbols are declared (intended for the application to use) it means that the application can't see them. This is a situation in which we need to propagate the exposed symbols from one level below a file to one level above the file. In other words, public symbols declared in a file that is included by win32lib, need to be made visible to the application that include win32lib.

This is achieved by having win32lib do a public include of its sub-library files. This is totally transparent to the application because conceptually, win32lib is the library file in which the exposed API is declared. So, from the point of view of the application, it needs to use a symbol from the win32lib library so it explicitly includes win32lib. This gives the application writer a consistant approach and frees the library writer to manage the multi-file library without breaking applications.

Having a multi-file library should make it easier for the library writer to organize the placement of routines so that related routines are near each other. This is a maintenance time-saver. However, in v3 Euphoria, this was not always possible due to the idea that code could only refer to other symbols that were 'above'. This meant that the physical placement of routines overrode the logical placement of routines. In large libraries, this could lead to situations were related routines are in different files, or widely separated in the same file. It also meant that a change to one routine's code might also mean you need to relocate that routine to get it to work again. The net result is the fragmentation of your library, which doesn't help readers or maintenance coding. The other technique to overcome this limitation is to use the routine_id() concept, but this comes with a performance overhead.

In v4, the limitation of where routines are placed has been lifted. One is no longer constrained to an artificial physical layout of code in order to get routines to 'see' each other. Instead, one can now group together related pieces of code.

Not all name clashes are resolved with public though. If two included files both declare the same exposed symbol name, your application needs a way to tell Euphoria which one you are referencing. This is done using the namespace concept. Each included file can have a namespace associated with it. This is just a name that you give to the file so you can qualify references to exposed symbols from that file. For example...

include foo.e as A 
include bar.e as B 
 
if A:func() = B:func() then ... 

In this case, both foo.e and bar.e declare an exposed symbol called 'func'. For Euphoria to know which 'func' you mean to use, you need to tell it via the namespace id. In this example, the namespace we gave to foo.e is 'A', and to bar.e is 'B'.

Actually, if the library writer has been on the ball, they would have given their files default namespaces and documented them of course too. For example ...

-- foo.e -- 
namespace foo 
 
public function func()  
   ... 
end function 
----- 
-- bar.e -- 
namespace bar 
 
public function func()  
   ... 
end function 
----- 

Then the application could have been written ...

include foo.e 
include bar.e 
 
if foo:func() = bar:func() then ... 

Note that these are default namespaces. You can still override them by using the "as" clause, if you want to.

new topic     » goto parent     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu