Let's say I have a state variable s.
I've got a .z.ws hook that responds to websocket messages and runs:
.z.ws: {handleMsg x}
Do I have to declare s as global for handleMsg to be able to update s?
Ideally, what I'd want is something like:
s: handleMsg[s;x]
where handleMsg is a pure function (it doesn't affect any globals on the inside).
Should I declare s as global and then try to do this assignment inside the websocket callback?
You don't pre-declare variables as global in kdb, they're global if you make them global at any point (and if you reference them as a global).
q)func:{x+1}
/s is local and treated as such
q){s:func[1]}[]
2
/it is not a global
q)s
's
/this would make it global
q){`s set func[1]}[]
`s
/or
q){s::func[1]}[]
/now it's global
q)s
2
/but a local of the same name would take preference
q){s:func[100];s}[]
101
q)s
2
/you can force-reference the global if required
q){s:func[100];value `s}[]
2
So you're in complete control over what's global, what isn't, when you're referencing a local and when you're referencing a global.
Related
In Matlab, it is easy to generate "help" for a function, as follows.
function out = foo()
% helpful information about foo
end
When we execute help foo, we get "helpful information about foo".
However, suppose we would like to define help for a variable, probably as a definition. How could we do such a thing? It would be nice if we could do something like
x = 3; % m ... position
help x
and get "m ... position". However, I don't believe such functionality exists.
The only reasonable way I see around this is to define every variable as a struct with keys value and description.
x.value = 3;
x.description = 'm/s ... position';
This requires we define every variable as a struct, which is kind of annoying and, I worry (should I?), unperformant (it's simulation code and these variables are accessed repeatedly).
Is there another solution I'm not considering? Should I be worried about making every variable a struct?
Your code should be self-documenting. Instead of variable name x, use position.
Furthermore, all variables should be local, so you can easily look for its definition (with comment) within the function you are editing.
Variables declared further away (with larger scope within the function) should have longer, more self-explanatory names than variables with a smaller scope (e.g. use within a short loop.
There are only two three cases where variables are declared outside the function’s scope:
Class properties. You can actually document these.
In a script, you have access to variables that already existed before the script started. A good reason not to use scripts or depend on the base namespace in larger projects.
Global variables. You should never use global variables for many reasons. Just don’t.
I am trying to write a perl script that calls a function written somewhere else (by someone else) which manipulates some of the variables in my script's scope. Let's say the script is main.pl and the function is there in funcs.pm. My main.pl looks like this:
use warnings;
use strict;
package plshelp;
use funcs;
my $var = 3;
print "$var\n"; # <--- prints 3
{ # New scope somehow prevents visibility of $pointer outside
local our $pointer = \$var;
change();
}
print "$var\n"; # <--- Ideally should print whatever funcs.pm wanted
For some reason, using local our $pointer; prevents visibility of $pointer outside the scope. But if I just use our $pointer;, the variable can be seen outside the scope in main.pl using $plshelp::pointer (but not in funcs.pm, so it would be useless anyway). As a side-note, could someone please explain this?
funcs.pm looks something like this:
use warnings;
use strict;
package plshelp;
sub change
{
${$pointer} = 4;
}
I expected this to change the value of $var and print 4 when the main script was run. But I get a compile error saying $pointer wasn't declared. This error can be removed by adding our $pointer; at the top of change in funcs.pm, but that would create an unnecessary global variable that is visible everywhere. We can also remove this error by removing the use strict;, but that seems like a bad idea. We can also get it to work by using $plshelp::pointer in funcs.pm, but the person writing funcs.pm doesn't want to do that.
Is there a good way to achieve this functionality of letting funcs.pm manipulate variables in my scope without declaring global variables? If we were going for global variables anyway, I guess I don't need to use dynamic scoping at all.
Let's just say it's not possible to pass arguments to the function for some reason.
Update
It seems that local our isn't doing any "special" as far as preventing visibility is concerned. From perldoc:
This means that when use strict 'vars' is in effect, our lets you use a package variable without qualifying it with the package name, but only within the lexical scope of the our declaration. This applies immediately--even within the same statement.
and
This works even if the package variable has not been used before, as package variables spring into existence when first used.
So this means that $pointer "exists" even after we leave the curly braces. Just that we have to refer to it using $plshelp::pointer instead of just $pointer. But since we used local before initializing $pointer, it is still undefined outside the scope (although it is still "declared", whatever that means). A clearer way to write this would be (local (our $pointer)) = \$var;. Here, our $pointer "declares" $pointer and returns $pointer as well. We now apply local on this returned value, and this operation returns $pointer again which we are assigning to \$var.
But this still leaves the main question of whether there is a good way of achieving the required functionality unanswered.
Let's be clear about how global variables with our work and why they have to be declared: There's a difference between the storage of a global variable, and visibility of its unqualified name. Under use strict, undefined variable names will not implicitly refer to a global variable.
We can always access the global variable with its fully qualified name, e.g. $Foo::bar.
If a global variable in the current package already exists at compile time and is marked as an imported variable, we can access it with an unqualified name, e.g. $bar. If a Foo package is written appropriately, we could say use Foo qw($bar); say $bar where $bar is now a global variable in our package.
With our $foo, we create a global variable in the current package if that variable doesn't already exist. The name of the variable is also made available in the current lexical scope, just like the variable of a my declaration.
The local operator does not create a variable. Instead, it saves the current value of a global variable and clears that variable. At the end of the current scope, the old value is restored. You can interpret each global variable name as a stack of values. With local you can add (and remove) values on the stack.
So while local can dynamically scope a value, it does not create a dynamically scoped variable name.
By carefully considering which code is compiled when, it becomes clear why your example doesn't currently work:
In your main script, you load the module funcs. The use statement is executed in the BEGIN phase, i.e. during parsing.
use warnings;
use strict;
package plshelp;
use funcs;
The funcs module is compiled:
use warnings;
use strict;
package plshelp;
sub change
{
${$pointer} = 4;
}
At this point, no $pointer variable is in lexical scope and no imported global $pointer variable exists. Therefore you get an error. This compile-time observation is unrelated to the existence of a $pointer variable at runtime.
The canonical way to fix this error is to declare an our $pointer variable name in the scope of the sub change:
sub change {
our $pointer;
${$pointer} = 4;
}
Note that the global variable will exist anyway, this just brings the name into scope for use as an unqualified variable name.
Just because you can use global variables doesn't mean that you should. There are two issues with them:
On a design level, global variables do not declare a clear interface. By using a fully qualified name you can simply access a variable without any checks. They do not provide any encapsulation. This makes for fragile software and weird action-at-a-distance.
On an implementation level, global variables are simply less efficient than lexical variables. I have never actually seen this matter, but think of the cycles!
Also, global variables are global variables: They can only have one value at a time! Scoping the value with local can help to avoid this in some cases, but there can still be conflicts in complex systems where two modules want to set the same global variable to different values and those modules call into each other.
The only good uses for global variables I have seen are to provide additional context to a callback that cannot take extra parameters, roughly similar to your approach. But where possible it is always better to pass the context as a parameter. Subroutine arguments are already effectively dynamically scoped:
sub change {
my ($pointer) = #_;
${$pointer} = 4;
}
...
my $var = 3;
change(\$var);
If there is a lot of context it can be come cumbersome to pass all those references: change(\$foo, \$bar, \$baz, \#something_else, \%even_more, ...). It could then make sense to bundle that context into an object, which can then be manipulated in a more controlled manner. Manipulating local or global variables is not always the best design.
There's too much wrong with your code to just fix it
You've used package plshelp in both the main script and the module, even though the main entry point is in main.pl and your module is in funcs.pm. That's just irresponsible. Did you imagine that the package statement was solely for advertising for help and it didn't matter what you put in there?
Your post doesn't say what is wrong with what you have written, but it's surprising that it doesn't throw an error.
Here's something close that does what you seem to expect. I can't really explain things as your own code is so far from working
Functions.pm
package Functions;
use strict;
use warnings;
use Exporter 'import';
our #EXPORT_OK = 'change';
sub change {
my ($ref) = #_;
$$ref = 4;
}
main.pl
use strict;
use warnings 'all';
use Functions 'change';
my $var = 44;
print "$var\n";
change(\$var);
print "$var\n";
output
44
4
I'd like to use the data that are loaded to my workspace in a Matlab function. This is the beginning of my function.
function [totalProfit] = compute(p,exit)
%% Declaration of variables
entry=0;
T = length(data);
.
.
.
end
I'm getting an error:
Undefined function or variable 'data'.
Where is the error?
The variable data was probably defined outside of the function, so it is out of scope.
Pass data as a parameter to compute and then it will be available inside the function.
You can use evalin to work with variables from another workspace. In your example this could be
T = evalin('caller','length(data)')
But please note that in most cases you get cleaner code if you define the variable as input argument for the function. So for your case this would be
function [totalProfit] = compute(p,exit,data)
T = length(data) ;
end
Ran is correct, but I wanted to mention something else. In general, only variables that are passed as arguments to a function are able to be used inside that function, so if you want to use your existing variables inside the function, pass them as input arguments.
It is possible to create global variables which allow you to use them inside functions without passing them as arguments, but it's usually not the best way of writing code. The times where I have used global variables are where I am calling multiple functions from a single script, and I have some constants that will be used by all the functions (for example gravity is a common one). An alternative to global variables is to use a struct, with the variables you want to pass to the function in it, so you only need one extra input argument, but you still have to be a bit careful.
Given the following code:
outer=1
f=->
local=1
outer=0
local+outer
coffeescript creates a var for local but re-ueses outer:
var f, outer;
outer = 1;
f = function() {
var local;
local = 1;
outer = 0;
return local + outer;
};
Which is what your expect.
However, if you use a local variable in a function it depends on the outer scope if the variable is declared local or not. I know this is a feature, but it was causing some bugs, because I have to check all outer scopes for variables with the same name (which are declared before my function). I wonder if there is a way to prevent this type of bug by declaring variables local?
This kind of error usually comes up when you aren't using appropriately descriptive variable names. That said, there is a way to shadow an outer variable, despite what the accepted answer says:
outer=1
f=->
do (outer) ->
local=1
outer=0
local+outer
This creates an IIFE, with outer as it's one argument. Function arguments shadow outer variables just like the var keyword, so this will have the behavior you expect. However, like I said, you should really just name your variables more descriptively.
No, that feature is explicitly not available in CoffeeScript (emphasis mine):
This behavior is effectively identical to Ruby's scope for local variables. Because you don't have direct access to the var keyword, it's impossible to shadow an outer variable on purpose, you may only refer to it. So be careful that you're not reusing the name of an external variable accidentally, if you're writing a deeply nested function.
You can inject plain JavaScript into your CoffeeScript using backticks:
outer=1
f=->
local=1
`var outer=0`
local+outer
For most cases I try to avoid this and would rather rename the outer variables, indicating their scope/context within their name. However, sometimes this is helpful, e.g., when using the debug module, where I always want to have a debug() function available for logging, as in this example:
#logging fn for module setup and other global stuff
debug = require("debug")("foo")
class Bar
#local logging fn to allow Bar instances to log stuff
`var debug = require("debug")("foo:bar")`
If you want to keep plain JS at a minimum just declare the variable and then assign is using CoffeeScript:
`var debug`; debug = require("debug") "foo:bar"
The example compiles to:
// Generated by CoffeeScript 1.7.1 -- removed empty lines for SO answer
var Bar, debug;
debug = require("debug")("foo");
Bar = (function() {
function Bar() {}
var debug;
debug = require("debug")("foo:bar");
return Bar;
})();
I like this direct way of declaring variables better than the (IMHO) slower and less readable IIFE hack.
As Aaron pointed out, shadowing is indeed possible:
outer=1
f=->
do (outer) ->
local=1
outer=0
local+outer
Since the outer value is not needed inside the local function, it can be initialized with null just in case that at some point the variable outer is removed from the outer scope (which would cause an error).
#outer=1
f=->
do (outer=null) ->
local=1
outer=0
local+outer
important = 10 # global
main = ->
agentId = '007'
console.log 'global `important`', important # refers to the global variable
((important) -> # place the local variables as the arguments
important = 20
console.log 'local `important`', important # locally scoped
console.log 'parent scope value', agentId # even access variables from the above scopes
)() # not passing anything, so the local varibales would be left undefined at first
console.log 'global `important`', important # the global variable remains untouched
main()
As I understand it, in order for the variables assigned to within a jasmine beforeEach to be accessible by the specs it applies to, the variables have to be declared in the containing block. I'm trying to find the least verbose way of doing this using coffeescript and came up with:
[var1, var2, var3, ..., varn] = [undefined]
Is there a better way?
You could drop the undefined I suppose:
[var1, var2, var3, ..., varn] = []
I can't think of anything else. And a better question to ask is why you need so many global-ish variables in the first place: if you need so many variables that explicitly defining them is onerous then maybe you have too many variables.