1. confusion about include
- Posted by Jerry_Story Aug 07, 2010
- 1370 views
The Euphoria 4.0 documentation, under "4.8.1 include" does not clearly explain "public" and "export".
What exactly do these lines do?
include file1.e public include file2.e export include file3.e -- Is there such a thing as global include file4.e
It used to be simple. Include something and it's included for all my files. What do I gotta do to make it work like it used to?
2. Re: confusion about include
- Posted by ne1uno Aug 07, 2010
- 1378 views
The Euphoria 4.0 documentation, under "4.8.1 include" does not clearly explain "public" and "export".
What exactly do these lines do?
include file1.e public include file2.e export include file3.e -- Is there such a thing as global include file4.e
It used to be simple. Include something and it's included for all my files. What do I gotta do to make it work like it used to?
export constant a=1 public b=1 global constant c=1
there is no global include.
a routine, constant or varb marked global will be in scope when the file it is in is included as well as any file that includes that one. but, there are advantages to only including those symbols that are actually required.
to have a routine marked export in filexyz.e in scope,
the file it is used in has to have at least an include filexyz.e
export include will also allow any files that include that second file to see export & public in the first file and then finally public include will only allow public symbols to be seen in the next level up.
That's how I've been looking at it.
a number of people, a number of times have attempted to clarify this on the forum and in the docs. I think probably a diagram would help if anyone is handy with graphviz. I do think the current docs do a decent job of explaining the differences but a few more shorter examples might help. give it a second read.
it would also help if you could set a flag to have euphoria run a quick analyze on a can't resolve symbol in scope error to suggest an include file you might try.
if you are say converting an older program to eu4 and have a bunch of symbols to resolve, you can run bin/analyze.ex and it can find some of them. eui bin/analyze.ex prog.ex
source/std.ex can also suggest include files to try in the same way as analyze.ex but I haven't kept up with the new commandline syntax required.
the latest version of the docs contains a javascript search field which should help. you will have to run off a copy of the docs yourself, the online docs are way out of date. I believe the makefiles have a single page doc target that works if you have grabed eudoc and creole from svn.
the euphoria chm from the archive can be setup with most editors to give context sensitive help from your editor.
it's harder to describe than to do.
3. Re: confusion about include
- Posted by Jerry_Story Aug 07, 2010
- 1368 views
In the good old days when Euphoria was simple, 'include' included files for the entire rest of the program. So I could do this:
-- main file include GtkEngine.e include myfile1.e -- GtkEngine.e would be recognized in each of these files. include myfile2.e include myfile3.e -- bunchuv code -- end main file
Now it's different:
-- main file include GtkEngine.e include myfile1.e -- GtkEngine.e must be included in each of these files. include myfile2.e include myfile3.e -- bunchuv code -- end main file
Is there a way to do 'include' in Euphoria 4.0 that works the same way as 'include' in Euphoria 3.1?
4. Re: confusion about include
- Posted by ne1uno Aug 07, 2010
- 1350 views
Now it's different:
-- main file include GtkEngine.e include myfile1.e -- GtkEngine.e must be included in each of these files. include myfile2.e include myfile3.e
Is there a way to do 'include' in Euphoria 4.0 that works the same way as 'include' in Euphoria 3.1?
guess I should have looked up export include in the docs. can't seem to find it. export include GtkEngine.e probably would have worked if export include ever existed.
if all the routines and varbs in GtkEngine.e are marked export, there is no choice but to have include GtkEngine.e in myfile1.e, myfile2.e, myfile3.e
the advantage is, these files will be able to be tested individualy for syntax and resolve symbol errors if nothing else. by eui -TEST file1.e
5. Re: confusion about include
- Posted by DerekParnell (admin) Aug 07, 2010
- 1358 views
The Euphoria 4.0 documentation, under "4.8.1 include" does not clearly explain "public" and "export".
What exactly do these lines do?
include file1.e public include file2.e export include file3.e -- Is there such a thing as global include file4.e
It used to be simple. Include something and it's included for all my files. What do I gotta do to make it work like it used to?
OK, I'll have a go at an explanation of how and why it works the way it does now.
This will be a lot of words but it's not really that complex is when you come to use it.
A bit if background first ...
Scope
A scope is block of code that can access a symbol. There are five levels of scoping in which symbols can be declared ...
- Application
- File (module)
- Routine
- if ... end if (Not in v3)
- loops (Only for ... end for in V3)
Version 3 Scope
A symbol is either private or global. It is private if it does not have the global keyword before the declaration.
private | : | Can be accessed by code in the same enclosing block as the declaration and by code in blocks defined inside the enclosing block. |
global | : | Can be accessed by anything in the application. |
The effect of these rules is that if a library writer wants applications to access a symbol in the library file. that symbol must be declared as 'global'. The side effect of this is that the symbol is now accessible by all modules in the application, and that can lead to interpreter errors when multiple libraries just happen to use the same 'global' identifier name. Most of these situations can be worked around by using the namespace qualifier but some situations can only be fixed by editing a third party library.
In other words, if your application includes AA.E then all global symbols, and only global symbols, declared inside AA.E can be accessed by your application. Furthermore, global symbols declared inside files that are in turn included inside AA.E are also accessible to your application. So if AA.E includes BB.E then your application can also see the globals declared inside BB.EE
Now consider large libraries like Win32Lib. This library consists of many files, some of which have symbols declared for internal usage only and applications are not really supposed to have access them. But in V3, you need 'global' to expose these internal-use symbols to other files within the library, and this inadvertently exposes them to the application and third-party included files too.
Version 4 Scope
The private and global scopes still exist with identical semantics in V4. However, additionally V4 has public symbols. A public symbol can only be declared at the file scope level and makes the symbol accessible by anything in the same file and by any file the directly includes it. Its kind of like the visibility is raised one level only.
For example, if CC.E declares a public symbol FOO and BB.E includes CC.E, then code in BB.E can access FOO. But if AA.E includes BB.E then code in AA.E cannot see FOO.
Let's go back to the Win32Lib library. In version 4, an application that wants to use the library has
include win32lib.ew
Now if win32lib.ew includes a file called structure.ew that has public symbols declared (eg. public function acquire_mem() ) it means that code in win32lib.ew can use acquire_mem(). Now, as that is a public symbol it means that the application cannot see the function, which is not the desired result.
In V4, we have introduced the public include statement. This has the effect of propagating any public symbols visible in the included file up one more level. So, in our example, win32lib.ew actually has public include structure.ew, which means that not only can code in win32lib.ew see the function, so can anything that includes win32lib.ew. It is not like global in that this propagation goes up one level only and not all levels.
By using public declared symbols, we decrease the chance of accidental name clashes between third party libraries.
Again, returning to the Win32LIb library. While the public include concept solves one problem for us, it doesn't solve the issue of preventing internal-use symbols from being exposed to applications. To overcome this, V4 has a slight variant of the public declared symbol; it can declare a symbol as export rather than public. The only difference is that export symbols are not propagated by the public include statement whereas public symbols are.
All these new refinements of scope are really of interest to library writers only. People writing applications would just use the simple include statement to get access to a library's API. Library writer would declare symbols as export if they are only intended to be used within a multi-file library's own include files, otherwise they would declare all symbols needed by an application as public and use the public include for its own internal include files.
global
After decades of computer programming research, it has been shown that 'global' symbols should be avoided because they increase maintenance costs and increase the chance of bugs. This will become increasingly obvious as multi-core architectures split an application up into parallel tasks, which frown on having shared symbols between tasks. I can envisage that a future version of Euphoria will implement multi-core support with symbols being 'thread-safe' by default and using 'global' symbols as shared data between threads.
I told a slight untruth before. In V4, the semantics of 'global' is a little different. Visibility is strictly limited to a reference's include tree. Let me illustrate...
The file DD.E contains the declaration global constant foo ... and BB.E includes DD.E so it can use its foo symbol. No problem there. Furthermore the file EE.E contains the declaration global procedure foo( ) and CC.E includes EE.E so it can use its foo symbol. Still no problem. Now, AA.EX includes BB.E. Still no problem. But when AA.EX also includes CC.E, version 3 Euphoria has a problem. The interpreter no longer knows which 'foo' BB.E wants to use - the one in DD.E or the one in EE.E which has suddenly become exposed by including CC.E.
---DD.E---------------- ---EE.E------------------- global constant foo = 1 global function foo() ... ----------------------- -------------------------- | | | | v v ---BB.E------------- ---CC.E----------- include DD.E include EE.E constant x = foo constant y = foo() -------------------- ------------------ \ / \ / \ / v v -----------AA.EX------------ include BB.E include CC.E ----------------------------
The version 3 interpreter allows BB.E to see the 'foo' declared in EE.E, even though it is not in the same include tree. In version 4, the interpreter realizes that BB.E doesn't know that CC.E, and thus EE.E, even exists so it doesn't raise a name clash error in BB.E (or CC.E for that matter).
Of course, a V4 library would be using public rather than global so it would never had been a problem anyway.
Cheating the System
Of course, if you want to revert to the poorer coding style of not having to directly include only the files that your application is using, there is a trick.
Create a file, let's call it ALL.E for this example, and let it only contain a list of public includes for the standard library ...
---- all.e ---- public include std/cmdline.e public include std/common.e public include std/complex.e public include std/console.e public include std/convert.e public include std/datetime.e public include std/dll.e public include std/eds.e public include std/error.e public include std/eumem.e public include std/filesys.e public include std/flags.e public include std/format.e public include std/get.e public include std/graphcst.e public include std/graphics.e public include std/image.e public include std/io.e public include std/lcid.e public include std/locale.e public include std/localeconv.e public include std/machine.e public include std/map.e public include std/math.e public include std/mathcons.e public include std/memconst.e public include std/memory.e public include std/mouse.e public include std/os.e public include std/pipeio.e public include std/pretty.e public include std/primes.e public include std/rand.e public include std/regex.e public include std/search.e public include std/sequence.e public include std/serialize.e public include std/sets.e public include std/socket.e public include std/sort.e public include std/stack.e public include std/stats.e public include std/task.e public include std/text.e public include std/types.e public include std/unittest.e public include std/utils.e public include std/wildcard.e --------------
Then all your applications ever have to include is ALL.E to get access to every public system in the standard library.
6. Re: confusion about include
- Posted by mattlewis (admin) Aug 07, 2010
- 1320 views
I told a slight untruth before. In V4, the semantics of 'global' is a little different. Visibility is strictly limited to a reference's include tree. Let me illustrate...
This is not quite correct. Global symbols are still global. However, the way in which we resolve these symbols has changed. Global symbols not in the current file's include tree will not be resolved until the end, and will be effectively hidden by other symbols in the include tree with the same name. When you include a file, you have access to all symbols in that file. In some circumstances, we find that two files include each other.
Consider the following code:
-- file a.e include b.e export integer foo bar() -- file b.e include a.e foo = 1 export procedure bar() ? foo end procedure
Here we have two files that include each other. In v3, this code wouldn't work, because the parser starts reading b.e as soon as it hits the first include statement. So when b.e tries to use foo, we get an error, because foo hasn't been declared yet.
But in v4, as I said, you have access to all symbols in any file you include, so it's perfectly fine to use foo from b.e.
Now, it's important to consider the way in which symbols are resolved. Euphoria prefers (and IIRC, this started in v3.1) to use a symbol that is in a file that has been included (directly or indirectly) from the file in which you're trying to use it. The main purpose for this is to help with using multiple 3rd party libraries. The net effect to the coder is that so long as he includes the files he wants to use, he shouldn't have to worry too much about getting symbol clashes. And if he does, he can use namespaces to make sure that he uses the right symbols.
When you follow this thought to global symbols, it becomes clear that if we find a matching global symbol that hasn't been included directly or indirectly by the current file, we still don't know that this is the correct symbol, because we may not have finished parsing all of the files that have been included by the current file. So we wait to fully resolve this until we're finished. This can also slow down parsing if your code relies on globals that haven't been included.
This makes developing euphoria a lot more difficult, but using it easier. The cost to you as the end user is that you'll probably have to write more include statements, but you should never have to rearrange the order of declarations and include statements to get everything to work out (though you still might occasionally need namespaces).
Matt
7. Re: confusion about include
- Posted by ChrisB (moderator) Aug 07, 2010
- 1289 views
The Euphoria 4.0 documentation, under "4.8.1 include" does not clearly explain "public" and "export".
What exactly do these lines do?
include file1.e public include file2.e export include file3.e -- Is there such a thing as global include file4.e
It used to be simple. Include something and it's included for all my files. What do I gotta do to make it work like it used to?
Hi
Still can keep it simple. Here's what I do, distilling out all the other stuff from Derek and Matt
1. old global still works, or use new export for functions / procedures / variables / constants (plea to devs - please make sure global stays working!) 2. for every 'new file' within your program, include the file that contains the function / procedure or global variable you want to access from your 'new file' 3. use of namespaces is entirely optional
Converted my 20000 + line vet program a while ago using these rules, and it works absolutely fine.
Someone is bound to say, 'yes, but what about the case when.....' - these are likely to be few and far between cases, and I'll cross those bridges when I come to them.
Chris
8. Re: confusion about include
- Posted by DerekParnell (admin) Aug 07, 2010
- 1290 views
This is not quite correct...
Thanks Matt.
The upshot is that now with V4, coders can be very clear about how their symbols are to be used and better coding practices can now be employed.
9. Re: confusion about include
- Posted by DerekParnell (admin) Aug 07, 2010
- 1277 views
... plea to devs - please make sure global stays working! ...
There is no plan or intention to remove 'global' from the language.
- It is needed for backward compatibility
- It is needed for those coders who prefer that coding style
- It may be needed in future to support shared data between (true) threads.
10. Re: confusion about include
- Posted by DerekParnell (admin) Aug 07, 2010
- 1270 views
The Euphoria 4.0 documentation, under "4.8.1 include" does not clearly explain "public" and "export".
What exactly do these lines do?
include file1.e public include file2.e export include file3.e -- Is there such a thing as global include file4.e
It used to be simple. Include something and it's included for all my files. What do I gotta do to make it work like it used to?
Sorry, Jerry. I also meant to directly answer your questions as well.
include file1.e
This allows access to all 'export', 'public' and 'global' symbols visible to 'file1.e'.
public include file2.e
This allows access to all 'export', 'public' and 'global' symbols visible to 'file2.e'. It also makes visible all 'public' symbols that are visible in 'file2.e', to files that include the current file.
export include file3.e
This is illegal and will cause a syntax error.
-- Is there such a thing as global include file4.e
No there is not.
It used to be simple. Include something and it's included for all my files. What do I gotta do to make it work like it used to?
Yes, simple to initially code but complex to manage.
You can still declare your symbols as 'global'. That hasn't changed.
If you want to use third party or standard libraries that are using 'public' or 'export' symbols, and use them as if these were global symbols, you need to use the 'trick' I mentioned.
Basically, create an all-inclusive file that 'public includes' all the libraries/modules you want to use, then in your applications, include your 'all' file. Note that this will not give you access to the 'export' symbols but that is a good thing as your application is not supposed to see those anyway. To force access to 'export' symbols, you still have to directly include them into your application file.
11. Re: confusion about include
- Posted by DerekParnell (admin) Aug 07, 2010
- 1269 views
In the good old days when Euphoria was simple, 'include' included files for the entire rest of the program. So I could do this:
-- main file include GtkEngine.e include myfile1.e -- GtkEngine.e would be recognized in each of these files. include myfile2.e include myfile3.e -- bunchuv code -- end main file
Now it's different:
-- main file include GtkEngine.e include myfile1.e -- GtkEngine.e must be included in each of these files. include myfile2.e include myfile3.e -- bunchuv code -- end main file
Is there a way to do 'include' in Euphoria 4.0 that works the same way as 'include' in Euphoria 3.1?
If the 'myfile' code is using stuff declared in GtkEngine.e and those declarations are 'public' or 'export' then yes, the 'myfile' files will need to directly include 'GtkEngine.e'.
Remember than the idea behind 'include' files is that these files are assumed to be re-usable modules that can be included into any file that needs access to the module's API. It is generally regarded as bad coding style to have implicit dependencies in a module on symbols declared outside the module. The 'global' concept allows that coding style if you want to use it though.
12. Re: confusion about include
- Posted by kinz Aug 07, 2010
- 1264 views
Version 3 Scope
A symbol is either private or global. It is private if it does not have the global keyword before the declaration.
private | : | Can be accessed by code in the same enclosing block as the declaration and by code in blocks defined inside the enclosing block. |
global | : | Can be accessed by anything in the application. |
Ok, but v3 docs say about "local" symbols too. And there are the rules about local and global symbols in a file. The local symbol has priority over the global one.
What do we have on that matter in v4?
kinz
13. Re: confusion about include
- Posted by mattlewis (admin) Aug 07, 2010
- 1232 views
Version 3 Scope
A symbol is either private or global. It is private if it does not have the global keyword before the declaration.
private | : | Can be accessed by code in the same enclosing block as the declaration and by code in blocks defined inside the enclosing block. |
global | : | Can be accessed by anything in the application. |
Ok, but v3 docs say about "local" symbols too. And there are the rules about local and global symbols in a file. The local symbol has priority over the global one.
What do we have on that matter in v4?
That hasn't changed. I think Derek mixed up private and local. Private symbols have scope inside of a routine. Local symbols are scoped to a file, and a local symbol takes precedence over an export, public or global symbols. Private symbols take precedence over all other symbols.
Matt
14. Re: confusion about include
- Posted by DerekParnell (admin) Aug 07, 2010
- 1274 views
Version 3 Scope
A symbol is either private or global. It is private if it does not have the global keyword before the declaration.
private | : | Can be accessed by code in the same enclosing block as the declaration and by code in blocks defined inside the enclosing block. |
global | : | Can be accessed by anything in the application. |
Ok, but v3 docs say about "local" symbols too. And there are the rules about local and global symbols in a file. The local symbol has priority over the global one.
What do we have on that matter in v4?
That hasn't changed. I think Derek mixed up private and local. Private symbols have scope inside of a routine. Local symbols are scoped to a file, and a local symbol takes precedence over an export, public or global symbols. Private symbols take precedence over all other symbols.
Matt
Correct, that hasn't changed but I didn't mention the term 'local' because I just wanted to concentrate of the difference between symbols that were being exposed outside of the file they were declared in.
15. Re: confusion about include
- Posted by Jerry_Story Aug 07, 2010
- 1232 views
OK, I'll have a go at an explanation of how and why it works the way it does now.
This will be a lot of words but it's not really that complex is when you come to use it.
A bit if background first ...
Thanks for the lengthy explanation. Could all that or something like that be added to the official Euphoria documentation?
16. Re: confusion about include
- Posted by ne1uno Aug 07, 2010
- 1255 views
In the good old days when Euphoria was simple, 'include' included files for the entire rest of the program. So I could do this:
-- main file include GtkEngine.e include myfile1.e -- GtkEngine.e would be recognized in each of these files. include myfile2.e include myfile3.e -- bunchuv code -- end main file
Now it's different:
thinking about your question a little more, and not having tried latest EUGTK4 available, if your main file is only going to use public and global symbols from GtkEngine.e and BTW, that is all it should ever need as a library consumer, then try it like this:
-- myfile1.e public include GtkEngine.e -- can use public, export in GtkEngine, and global routines from EUGTK4 -- passes only public, and global routines to any file that does include file1.e -- more code -- end myfile1.e -- main file include myfile1.e -- set up Gtk include myfile2.e -- needs include GtkEngine.e to use export or public GTK -- here can use public,and global EUGTK4 routines, none of export -- bunchuv code -- end main file
EUGTK4 local --x-- file1 EUGTK4 export ----> file1 --x-- main EUGTK4 global ----> file1 -----> main -----> EUGTK4 public ----> file1 -----> main --x-- EUGTK4 export --x-- file2 EUGTK4 global ----> file2 ----> file3 EUGTK4 public --x-- file2