After spending the week learning Lua, I was a bit shocked to encounter this weird scenario, since I had previously imagined that the "require" command worked just like a #include in C/C++ (i.e., it's copy/pasted in by the preprocessor).
Obviously that's not the case.
Here's what stumped me:
-- a.lua
this_is_global = "I'm a global var!!"
require "b"
print(global_in_b) -- error??!! globals in b aren't truly global?
-- b.lua
print(this_is_global) -- prints "I'm a global var!"
-- so b can see globals from a
global_in_b = "Am I global too?"
For productivity reasons I've just been creating my own table to act as a scope in b, adding everything I want to access to that table, and then returning the table in b so that I can write:
-- a.lua
stuff_from_b = require "b"
print(stuff_from_b.global_in_b) -- does what we want, in a weird way
I know I can also manually add stuff in b.lua to the _G table to force them to be global, but that feels ugly.
So my questions:
What's exactly happening with "globals" in required files? What table do they end up in if not _G?
What're the commonly accepted ways of accessing scopes of required files?
Neither require nor dofile are equivalent to include: both run code at run time, not textually add source code during compilation.
The globals that a required file sees are the same as the globals in the file that required it.
To avoid pollution and to allow privacy and hiding, it is good practice that Lua modules create and return a table with what they want to export to the external world. It is up to the designer of the module to decide what can be seen from the outside.
Related
The two functions mkYesodData and mkYesodDispatch in the Yesod framework are supposed to separate the handler definition and the dispatch process. Though by some miracle (to me), templates use this interesting function "resourcesApp":
mkYesodDispatch "App" resourcesApp
The only mention of this function I have found in hoogle is in the Hledger package. And it is not a yesod dependency.
In the school of Haskell by this link they give an explanation that resourcesApp is "generated" by mkYesodData, although it still does not work for my side.
https://www.schoolofhaskell.com/school/advanced-haskell/building-a-file-hosting-service-in-yesod/part%202
What is the reason for this?
There's some Template Haskell (TH) going on under the hood in Yesod, and I think this is what's confusing you. Template Haskell can be confusing when searching in documentation because it produces values at compile-time for use at runtime that aren't there before the code is compiled. resourcesApp is just one of these values.
In the code you reference, the author describes that you must have another module (which he calls Foundation) in which you have invoked mkYesodData. Indeed, without this other module, the code in the Dispatch module won't work. Strangely, it's not until (Part 4)[https://www.schoolofhaskell.com/school/advanced-haskell/building-a-file-hosting-service-in-yesod/part%204] that he seems to define the Foundation module, but you can see that there is a line:
mkYesodData "App" $(parseRoutesFile "config/routes")
That may not look like it defines a value called resourcesApp, but sure enough, it does.
In short, you should be able to get your code working by just finishing the entire tutorial and running the code altogether.
In case you're wondeering, a call to mkYesodData takes a String and then literally generates code that defines a value names resources**** where the **** is the string you passed. In this case, that would be a value resourcesApp, but in someone else's Yesod project, it could be resourcesFoo. Furthermore, since this resourcesFoo value isn't concretely in the code, projects that use Yesod typically wouldn't have it show up in their export lists or haddock documentation. It's actually very strange that you found even one hit for resourcesApp on hoogle at all, but upon closer examination, it kind of makes sense: Hledger seems to be some sort of extended interface around yesod, so they pre-generated the TH values so that they would be easily accessible to users.
As another note, TH has some restrictions in its use. For one, you typically need to perform the TH invocations ("splices" as they're typically called) in a separate module than the one you use the generated values. This is probably why the author has you create a separate Foundation module rather than just putting the line mkYesodData ... in the Dispatch module.
Im trying to accomplish a twincat 3 library which does things using global constants defined in the main project, like creating arrays the size of those constants and cycling trough them. However I've been unsuccessful and I wonder if this can be done. I just get this error "Error 4 Border 'cPassedConstant' of array is no constant value" when I try to build the main project. The error comes from the array defined in the library.
I've tried making a GVL with a constant of the same name to the library and then setting the "external implementation" property true but that does not help.
My goal here is to make a IO management library with filtering and such. And then I could just add it to the main project and define some constants like "cDigitalIputsCount","cAnalogInputCount" and so on.
Maybe you can get along with the new ARRAY[*] feature instead, although it is still very limited. There is no other way than to define the constant in the library.
The library concept is the same as in other environments. A library provides you reusable components. Your main project depends on the library and not the other way around. Therefore your library cannot know a thing about the project where it is used.
A confusing thing in TwinCat3 is, that you can build projects successful with programming errors inside. The TwinCat3 compiler allows broken code inside a project as long as it is not called. Therefore when you ship libraries you should always use "Check all objects".
You should check Beckhoff's feature called Parameter List. By adding a parameter list to the library project, you can re-define library constants in the project that uses the library. The definition happens in the library manager.
Image from Beckhoff's site:
I think that should do it. Of course, the other option is to use the ARRAY[*] option, which is awesome too (for a PLC programming world). The problem with parameter lists is that it is a project-wide re-definition. Using the ARRAY[*] allows the size be changed dynamically.
I would suggest using a variable length ARRAY[*], as explained in the link below (and also in the Beckhoff/Infosys, section DataTypes/Array).
The point is that you should declare the ARRAY[1..cAINs] of FB_AnalogIO in your main program (it knows the FB_AnalogIO from your analog library and can declare it with a constant size).
The PRG_IO should then be changed to either a function or function block, so that it accepts the ARRAY[*] as a VAR_IN_OUT without knowing the exact size.
https://stefanhenneken.wordpress.com/2016/09/27/iec-61131-3-arrays-with-variable-length/
I have
root/Main.hs :
import ADT.Stack
main :: IO ()
main =
putStrLn "Hi"
root/ADT/Stack.hs
module Stack (Stack, empty, isEmpty, push, top, pop) where
...
Upon loading Main.hs, I have the error
File name does not match module name: …
Saw: ‘Stack’
Expected: ‘ADT.Stack’
If I change the module name to ADT.Stack in Stack.hs, I can get rid of the error.
However, I dont understand the reason behind such constraint.
Is there no way to avoid specifying in the code of Stack.hs what is already encoded in the name of the directory in which it is contained ?
If there are no alternative way, is there any good reason this ?
If you're using the hierarchical namespaces, your module names should reflect the full path. So, in root/ADT/Stack.hs, you should have
module ADT.Stack (Stack, empty, isEmpty, push, top, pop) where
After that, as you have observed, everything should be fine.
I am not aware of any possibility to derive the module name not only from the name you give it in the file, but also on the location of the file. (That is what you are after, aren't you?) Of course, this should be possible with some fancy preprocessing, but you probably don't want to go there.
So, then, why are things like they are? Not sure whether, for you, it qualifies as a good reason, but one can argue that this scheme has as an advantage that by simply moving a file to another directory you don't silently break any client codes. Instead, you get an error already when compiling the moved file.
The redundancy in the file location and the module name allows processors to find imported modules with only a minimal set of "search paths". Also, it provides a standard for organising source files over larger projects.
I use haddock and don't want all of my exported functions to be displayed in the documentation. Is it possible to hide specific functions?
I found the prune attribute at http://www.haskell.org/haddock/doc/html/module-attributes.html, but this is not what I want since some functions which shall be exported don't have a documentation annotation.
Assuming your current module is Foo.Bar, one solution would be to break it up into Foo.Bar and Foo.Bar.Internal. You could move all the definitions related to the function you don't want to export--perhaps even all the definitions--into Foo.Bar.Internal. Then, in Foo.Bar, you would re-export only the definitions you want the world to see.
This approach has a couple of advantages. It lets you export everything you need, while still giving the user a clear sign that certain things shouldn't be used. It also lets you document your special functions inside the Internal module, which is going to be useful (if only for your future self :P).
You could simply not export Foo.Bar.Internal in your .cabal file, hiding it from the world. However, this is not necessarily the best approach; look at the answers to How, why and when to use the ".Internal" modules pattern?, in particular luqui's.
Another possibility is to make a module Foo.Bar.Hidden exporting all of the stuff you want to hide, and then re-export the whole Foo.Bar.Hidden module from Foo.Bar:
module Foo.Bar (
blah1,
blah2,
blah3,
module Foo.Bar.Hidden
)
where
import Foo.Bar.Hidden
blah1 = ...
blah2 = ...
blah3 = ...
This way, the hidden stuff will be exported from Foo.Bar, but not included in the documentation. The documentation will only include one relatively unobtrusive link to the Foo.Bar.Hidden module as a whole.
With Java on one side and Ruby/Groovy on the other, I know that in the second camp I'm free to make typos which will not get caught until run-time. Is this true of all dynamically-typed languages?
Edit: I've been asked to elaborate on the type of typo. In Ruby and in Groovy, you can assign to a variable with an accidental name that is never read. You can call methods that don't exist (obviously your tests should catch this, it's been said). You can refer to classes that don't exist, etc. etc. Basically any valid syntax, even with typographical errors, is valid in both Ruby and Groovy.
In Perl, if you declare use strict in your code, then you must declare your variables with my. Typos in variable names will then be caught at compile-time. This is one of the biggest things I miss when coding in Python.
Python is typo-friendly in the way you described in your question.
But this does not mean that these 'typos' can only be caught # runtime.
When using a code analyzer like pylint (ideally integrated into your development environment) you'll catch 'most' of these consistently before hitting 'run'.
For the most part, yes. Dynamic typing and not requiring declaration of variables are language properties that are frequently found together.
However, these are not inherently related. A language can easily have dynamic typing while requiring variable names to be declared before use. As ire_and_curses mentions, this can be achieved in Perl via the "use strict" directive.
Here's what happens when I try to get into the pitfalls you mentioned in Squeak and Dolphin, two implementations of the dynamic language Smalltalk 80.
You can assign to a variable with an accidental name that is never read
The Smalltalk language requires temp and instance variables to be declared. If I try to compile a method containing an undefined variable I get a compile-time error.
| anArray |
anArrray := Array with: 2 with: 1. "Unknown variable anArrray"
Creating variables dynamically is not something dynamic languages have to allow. There's a difference between typeless declarations and no declaration at all.
You can call methods that don't exist
The compiler issue a warning if you use a selector (i.e. method name) that is entirely unknown.
The compiler won't bother if I call the method paint on an array because there's another class in the system implementing paint. That error will only be caught at runtime.
If however I call the method sortt (while I intend to call sort) the compiler generates a warning. When developing top-down you can proceed pass these warnings.
| anArray |
anArray := Array with: 2 with: 1.
anArray paint. "Runtime error. You can't paint an array but perhaps a Shape"
anArray sortt. "Compile-time warning"
You can refer to classes that don't
exist
This is not allowed. Though in Squeak you can quickly create a new class from the error dialog if needed.