While running the following:
foreach Var {Item1 Item2 Item3} {
# Do something
}
The variable 'Var' have the value of 'Item3'. Is there an option to auto-unset it or I'll have the unset it manually?
The reason for asking is that I define multiple namespaces by using 'foreach' statement and it leaves me a lot of un-needed variables around.
Specifically, I need to define some variables in a namespace:
namespace eval ::Bla {
foreach Var {Item1 Item2 Item3} {variable $Var}
}
Is there a way to re-write the code which does not leave the 'Var' set rather than unset it manually?
The scope of variables is either the procedure(-like thing, so this also includes lambdas and methods) or the namespace (and the global scope is just a namespace). The foreach command does nothing at all with defining scopes; Tcl has never worked that way, and I wouldn't expect it to change any time soon. If you want one of the iteration variables removed (foreach can have multiple such variables) then you'll have to unset it yourself.
foreach Var {Item1 Item2 Item3} {
# Do something
}
unset Var
I advise always using foreach inside a procedure (lambda, method) if you're doing anything complicated. It goes faster.
For your specific problem, you could put the namespace initialization code into a proc so it goes away when the proc ends.
proc createNamespaceVars {ns args} {
namespace eval $ns {
foreach Var $args {variable $Var}
}
}
But there is no magic unset switch as already explained by Donal.
Related
I'm trying to change the behavior of a Lua function, by adding code to the start or end of it. Because this is a mod for a game, I can't edit the function directly, so I have to override it instead. I accomplish this by storing a reference to the original function in a local variable, then redefining the function with my own, which calls the original one along with any prefix or postfix code I need to add, like so:
local base_exampleFunction = ExampleBaseGameClass.exampleFunction
function ExampleBaseGameClass.exampleFunction(param1, param2)
--Prefix code goes here
base_exampleFunction(param1, param2);
--Postfix code goes here
end
This works fine for functions defined with the ClassName.functionName syntax, but some functions use ClassName:functionName instead, which from what I understand, are functions that pass a reference to the class instance as the first parameter. I can't figure out how to prefix/postfix these functions, as I get the following error when declaring a variable to hold the original function if I try the same approach:
attempted index: exampleFunction of non-table: null
Is there a way to make this work?
: functions are just scary ways of saying "the first argument is self".
So, ExampleBaseGameClass:exampleFunction(param2) is equivelent to ExampleBaseGameClass:exampleFunction(ExampleBaseGameClass, param2)! It's just got self at the beginning, and functions declared with : will have an invisible self variable appear out of nowhere.
local a = {}
function a.b(self)
print(self)
end
function a:c()
print(self)
end
-- a.c(a) == a:c()
-- a:b() == a.b(a)
-- a:b() == a:c()
Using this idea, we can simply prepend an argument (it does not have to be called "self", it just has to be the first argument).
This should work, unless there is a part of your Lua environment (eg, funky metatables) which would prevent such a thing:
local base_exampleFunction = ExampleBaseGameClass.exampleFunction
function ExampleBaseGameClass.exampleFunction(self, param1, param2)
--Prefix code goes here
base_exampleFunction(self, param1, param2);
--Postfix code goes here
end
The lua library takes advantage of the first argument being the calling object for it's string library. Notice how ("hello"):gsub() works--by passing the string itself as the first argument!
We have a script in our Jenkins shared pipeline code which works along these lines, in src/Utils.groovy:
boolean isBuildNumberEven() {
int number = env.BUILD_NUMBER as int
(number % 2) == 0
}
This script is then used like this from one of the scripts in vars/
Utils utils = new Utils()
if (utils.isBuildNumberEven()) {
// Do something differently
}
The key point is that env apparently can be used with no problem.
Now I want to clean up the code and explicitly declare the class, so I change src/Utils.groovy like so:
class Utils {
boolean isBuildNumberEven() {
int number = env.BUILD_NUMBER as int
(number % 2) == 0
}
}
Now, I get an error about env being accessed as a global while it is not a global.
The Groovy compiler itself obviously knows how to convert a script with no class into a class, but I haven't quite figured out how to do it myself.
Is there a trick to allow me to access those global variables from the class, other than the obvious one of passing them all in via the constructor? Is there some global class somewhere which contains them all perhaps?
(Note that although I have used env for this example, it is not the only one I need to access. So yes, I already converted these to use System.getenv, but then immediately hit some other variable we were using. So there's no easy way out.)
I would like to do something like:
DEFAULT_CLUSTER_ALIASES = {
"local": "$(DEFAULT_LOCAL_CLUSTER)",
}
def helm_action(**kwargs):
if not "$(DEFAULT_LOCAL_CLUSTER)":
DEFAULT_LOCAL_CLUSTER = "docker-desktop"
_helm_action(
cluster_aliases = DEFAULT_CLUSTER_ALIASES,
**kwargs
)
IOW, if DEFAULT_LOCAL_CLUSTER is not defined, DEFAULT_CLUSTER_ALIASES will be dict("local": "docker-desktop").
and if --define=DEFAULT_LOCAL_CLUSTER=minikube, DEFAULT_CLUSTER_ALIASES will be dict("local": "minikube").
So far, I haven't been able to get the Make variable to be evaluated and DEFAULT_CLUSTER_ALIASES is dict("local": "$(DEFAULT_LOCAL_CLUSTER)").
What's needed so the Make variable is evaluated?
"make variables" are only evaluated in the context of rule attributes that support make variable substitution. See https://bazel.build/reference/be/make-variables#use
If helm_action is a macro, or is used from a macro, then this won't work because macros don't have access to configuration information (e.g. values from flags). If helm_action is used from a rule implementation, then you can access values set using --define from ctx.var: https://bazel.build/rules/lib/ctx#var
Another way to do this is to use Starlark flags: https://bazel.build/rules/config#user-defined-build-settings Though again, it depends on if you're writing a macro or a rule.
I have trouble understanding Nix overlays and the override pattern. What I want to do is add something to "patches" of gdb without copy/pasting
the whole derivation.
From Nix Pills I kind of see that override just mimics OOP, in reality it is just another attribute of the set. But how does it work then? Override is a function from the original attribute set to a transformed one that again has a predefined override function?
And as Nix is a functional language you also don't have variables only bindings which you can shadow in a different scope. But that still doesn't explain how overlays achieve their "magic".
Through ~/.config/nixpkgs I have configured a test overlay approximately like this:
self: super:
{
test1 = super.gdb // { name = "test1"; buildInputs = [ super.curl ]; };
test2 = super.gdb // { name = "test2"; buildInputs = [ super.coreutils ]; };
test3 = super.gdb.override { pythonSupport = false; };
};
And I get:
nix-repl> "${test1}"
"/nix/store/ib55xzrp60fmbf5dcswxy6v8hjjl0s34-gdb-8.3"
nix-repl> "${test2}"
"/nix/store/ib55xzrp60fmbf5dcswxy6v8hjjl0s34-gdb-8.3"
nix-repl> "${test3}"
"/nix/store/vqlrphs3a2jfw69v8kwk60vhdsadv3k5-gdb-8.3"
But then
$ nix-env -iA nixpkgs.test1
replacing old 'test1'
installing 'test1'
Can you explain me those results please? Am I correct that override can just alter the "defined interface" - that is all parameters of the function and as "patches" isn't a parameter of gdb I won't be able to change it? What is the best alternative then?
I will write an answer in case anyone else stumbles on this.
Edit 21.8.2019:
what I actually wanted is described in https://nixos.org/nixpkgs/manual/#sec-overrides
overrideDerivation and overrideAttrs
overrideDerivation is basically "derivation (drv.drvAttrs // (f drv))" and overrideAttrs is defined as part of mkDerivation in https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/make-derivation.nix
And my code then looks like:
gdb = super.gdb.overrideAttrs (oldAttrs: rec {
patches = oldAttrs.patches ++ [
(super.fetchpatch {
name = "...";
url = "...";
sha256 = "...";
})
];
});
The question title is misleading and comes from my fundamental misunderstanding of derivations. Overlays work exactly as advertised. And they are probably also not that magic. Just some recursion where endresult is result of previous step // output of last overlay function.
What is the purpose of nix-instantiate? What is a store-derivation?
Correct me please wherever I am wrong.
But basically when you evaluate Nix code the "derivation function" turns a descriptive attribute set (name, system, builder) into an "actual derivation". That "actual derivation" is again an attribute set, but the trick is that it is backed by a .drv file in the store. So in some sense derivation has side-effects. The drv encodes how the building is supposed to take place and what dependencies are required. The hash of this file also determines the directory name for the artefacts (despite nothing was built yet). So implicitly the name in the nix store also depends on all build inputs.
When I was creating a new derivation sort of like Frankenstein based on tying together existing derivations all I did was create multiple references to the same .drv file. As if I was copying a pointer with the result of getting two pointers pointing to the same value on the heap. I was able to change some metadata but in the end the build procedure was still the same. Infact as Nix is pure I bet there is no way to even write to the filesystem (to change the .drv file) - except again with something that wraps the derivation function.
Override on the other hand allows you to create a "new instance". Due to "inputs pattern" every package in Nix is a function from a dependencies attribute set to the actual code that in the end invokes the "derivation function". With override you are able to call that function again which makes "derivation function" get different parameters.
I have a file setup like this:
main.lua (requires 'mydir.b' and then 'b')
b.lua
mydir/
b.so (LuaJIT C module)
From main, I do this:
function print_loaded()
for k, v in pairs(package.loaded) do print(k, v) end
end
print_loaded()
require 'mydir.b'
print_loaded()
-- This would now include 'mydir.b' instead of 'b':
local b = require 'b'
The outputs of the prints show that my call to require 'mydir.b' is setting the return value as the value of package.loaded['b'] as well as the expected package.loaded['mydir.b']. I wanted to have package.loaded['b'] left unset so that I can later require 'b' and not end up with the (in my opinion incorrectly) cached value from mydir.b.
My question is: What's a good way to deal with this?
In my case, I want to be able to copy around mydir as a subdir of any of my LuaJIT projects, and not have to worry about mydir.whatever polluting the module namespace by destroying any later requires of whatever at the parent directory level.
In anticipation of people saying, "just rename your modules!" Yes. I can do that. But I'd love to know if there's a better solution that allows me to simply not have to worry about the name collisions at all.
The problem was that I was calling luaL_register incorrectly from within my b.so's source file (b.c).
Here is the bad code that caused the problem:
static const struct luaL_reg b[] = {
/* set up a list of function pointers here */
};
int luaopen_mydir_b(lua_State *L) {
luaL_register(L, "b", b); // <-- PROBLEM HERE (see below)
return 1; // 1 = # Lua-visible return values on the stack.
}
The problem with the highlighted line is that it will specifically set package.loaded['b'] to have the return value of this module when it's loaded. This can be fixed by replacing the line with this:
luaL_register(L, "mydir.b", b);
which will set package.loaded['mydir.b'] instead, and thus leave room for later use of a module with the same name (without the mydir prefix).
I didn't realize this until long after I asked this question, when I finally got around to reading the official docs for luaL_register for Lua 5.1, which is the version LuaJIT complies with.