I have a namespace variable which is defined as below:
namespace eval ::SMB::{
variable SmbInfo
------
------
proc ::SMB::SmbCreate {name dutport} {
variable SmbInfo
global DutPorts DutPort_2 DutPorts_3 smb
------
------
if{"" != [info command SMB::$name]} {
return -code error "command name \"$name\" already exists"
}
set SmbInfo($name -DutPort) $dutport
I am new to Tcl and trying to understand the above piece of code. Few questions, please correct me if I am wrong at any point:
The variable SmbInfo defined on top in namespace is getting overridden by the one declared in the procedure SmbCreate. I am unable to figure out what is the objective of the line:
set SmbInfo($name -DutPort) $dutport
I can see that 'DutPorts' is defined as global but I could not find 'DutPort'. I have not executed the code yet. Could it be an error?
Is ($name - DutPort) creating an array index for the variable SmbInfo and the value of $dutport is being set to that particular array variable?
I have similar code structures in the file like below
set SmbInfo($name - SmbSetDmac) [BuildMac1 $SmbInfo($from_name-DutPort)]
Where BuildMac1 is a procedure. A bit explanation of the above code might also make the thing clear.
If anything I missed to post in the question, kindly point me, I will edit my question.
Thanks in advance.
The second declaration doesn't override, it's the same variable in both cases.
The command is a syntax error because of the space after $name. The intent seems to be to assign the value of $dutport to the member of SmbInfo that has the name "$name -DutPort" (where $name is replaced by the variable value).
A similar assignment, but here the value comes from the result of the command.
There are a few syntax errors in the code, too many or too few spaces here and there. It seems unlikely this code has ever been executed.
The purpose of the smb::SmbCreate command would seem to be to 1) create a new command in the SMB namespace named by the first parameter (unless such a command already exists) and 2) store metadata in the SmbInfo namespace variable, indexed by a) the name parameter and b) a keyword such as -DutPort or -SmbSetDmac.
Code like this essentially implements an ad-hoc object-oriented interface. If the whitespace issues are resolved, it should work fine.
You have many syntactic problems that are going to cause you much grief. Tcl cares very much about its syntax level, which includes exactly where the spaces and newlines are, and whether there are {braces} and [brackets] as expected. You must get these things right.
Looking at the specific code you're having problems with, this line:
set SmbInfo($name -DutPort) $dutport
would appear to be highly unlikely, as it is passing three arguments to the set command when that only takes one or two. I'd guess that you've got a command that you're calling to obtain a key for an array, and that the code therefore ought to be this:
set SmbInfo([$name -DutPort]) $dutport
See those [brackets]? They matter here, as they say “run my contents as a little subscript and use the result”. With that sorted out, there's also the question of whether $name -DutPort works at all, but you'll just have to be guided by the error messages there. Tcl usually gives very good error messages, though sometimes you have to think about why the code got in the state where it is giving that message in order to figure out what the actual problem is. You know, usual debugging…
I would expect similar problems with:
set SmbInfo($name - SmbSetDmac) [BuildMac1 $SmbInfo($from_name-DutPort)]
and would guess that it is actually supposed to be:
set SmbInfo([$name -SmbSetDmac]) [BuildMac1 $SmbInfo([$from_name -DutPort])]
Note again that I have modified the spaces to follow the existing pattern (which I'm guessing is a property access; it looks like it's OTcl or XOTcl) and added brackets.
Finally, this line:
if{"" != [info command SMB::$name]} {
is also syntactically wrong, and should instead be:
if {"" != [info command SMB::$name]} {
That extra space matters, because it separates the word that is the command name (if) from the word that is the condition expression. The remainder of the line is probably correct (the SMB::$name might be suspicious, except you're using it in info command, but then you probably only need info command $name as it already knows about what namespace you're working in and you're using the unqualified name elsewhere).
Related
I wonder if it is right semantics to have a variable as an argument, something like this:
proc p1 {$aa} {}
I tried it on tclsh, there is no complaint, but the following experiment fails:
% set aa bb
bb
% set bb 200
200
% proc p1 {$aa} {puts $bb}
% p1 bb
can't read "bb": no such variable
Do you see what is wrong?
[UPDATE - after seeing Peter's answer]
I know the upvar semantic, thanks.
My main curiosity is still around using variable as proc argument. I know it is not common, but just cannot help musing what it really can do if the language syntax allows it.
Yes, your upvar example is exactly what I want to explore using a variable as proc argument, but my exploration so far tells me, really, there is no way we can do this because "$" is interpreted as a plain char.
Do debunk me please if I am wrong.
Tcl does not support reference arguments as such: the usual pass-by-reference semantics is too static for Tcl. Instead, the logic of the command can, by use of upvar, dynamically create reference parameters including indirect reference parameters and calculated reference parameters, and also retarget the local name to another external variable. The upvar mechanism may look ungainly, but is very powerful indeed.
(The (edited) remains of my original answer follows:)
The usual idiom for doing this is
proc p varName {
upvar 1 $varName var
puts $var
}
The upvar command looks into another stack frame (in this case 1, which is the caller's stack frame) and makes a variable named $varName (i.e. the variable's name is the value of varName) in that stack frame and a variable named "var" in the command's stack frame refer to the same data object.
I won't explain this further since this is not useful to the asker.
Documentation: proc, puts, upvar
There are cases where it makes sense for the arguments in a procedure creation call to be supplied from a variable. The main example is where you are creating procedures dynamically, calculating the arguments you want to use as you go along.
That's actually a use-case that isn't done very frequently! It's not particularly easy to use well. But I have done it. (OK, that's a method call, but the syntax of formal arguments is shared.)
The main reason that the capability is there is that it's part of Tcl's general syntax. Tcl tries very hard to not have special cases in how it parses things (other than in how a command parses the strings passed into it) and this includes in things that would be very special cases in the enormous majority of other programming languages, such as formal parameter lists to procedures. In Tcl, these are just ordinary values and can be produced using any technique that gives ordinary values.
The usual thing with putting them in braces is just how you do it reliably and is easy to teach. It's also overwhelmingly what people want to do.
All this is independent of the facts that Tcl's commands (including its procedures) can handle variable numbers of arguments (check out the special args parameter and how to specify default values) and that $aa is a legal (but strange) name for a local variable.
I have code that looks like this:
var variableX:uint = something;
if (variableX > 1)
{
var variableY:uint = foo;
}
else
{
var variableY:uint = bar;
}
When compiled in FlashDevelop, the compiler gives the following warning:
Warning: Duplicate variable definition.
Being a beginner with AS3 and programming I don't like compiler warnings. The compiler is looking at me through squinted eyes and saying "Ok, buddy, I'll let you off this time. But I'm warning you!" and then doesn't tell me what's so wrong about what I'm doing.
What should I be aware of when I do something like this? I mean I could obviously define the variable outside of if and then this wouldn't be a problem, but maybe there's something more to this? Or is the compiler just giving a helpful nudge saying "hey, you might have accidentally created two different variables with the same name" ?
You're correct in your assessment of the warning. It's just letting you know there was already a variable in scope with that name and that you're about to redefine it. This way you don't accidentally overwrite a variable. Although they may not appear to be in the same scope if you check out variable hoisting on this page you'll see what the deal is: http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f9d.html
An interesting implication of the lack of block-level scope is that
you can read or write to a variable before it is declared, as long as
it is declared before the function ends. This is because of a
technique called hoisting , which means that the compiler moves all
variable declarations to the top of the function. For example, the
following code compiles even though the initial trace() function for
the num variable happens before the num variable is declared:
My personal tendency is to just bring the definition up top myself to avoid having extra warnings that make me miss more important issues. Been out of AS3 for a while but in large projects people let things go and you end up with 100s-1000s of warnings and relevant ones get buried.
I have a curious case of Tcl that perhaps I just don't understand.
The following code is done at the top level (not inside of any procedure):
if {![info exists g_log_file_name]} {
set g_log_file_name "default.txt"
}
What I hope it would do is to declare a global variable with some value if it wasn't declared yet (which can be done at some other script or C application). However, the if statement always false. I ran on Tcl 7.4.
What may be the problem?
Thank you so much.
% info level
0
% info exists g_log_file_name
0
% set g_log_file_name whatever
whatever
% info exists g_log_file_name
1
Hence the reason you observe is probably because the variable is really always unset at the time your if command is executed.
Possible reasons for this I can imagine are:
It's just not set: literally, no code attempt to do this;
The external code sets some other variable: name mismatch;
The external code sets a variable in some other interpreter: in a C code embedding Tcl, there can be any number of Tcl interpreters active at any moment (and those are free to create child interpreters as well);
I'm not sure abot the long forgotten version of Tcl you have at hand, but 8.x has the trace command which can be used to log accesses to a particular variable—you could try to use it to see what happens.
I $P(GIH,,24)= S $P(GIH,,24)="C" S
What is the meaning of two S's in above MUMPS statement?
Let me start out by saying the original statement is NOT either Standard MUMPS or InterSystems Cache, or GT.M code. Even broadly guessing what was originally meant, the final S on the line isn't something you would do in MUMPS. A single S could be a SET command, but you still don't have any arguments telling what variable could be assigned, or what value should be assigned to it.
The rest of my reply is trying to figure out what it could have meant.
Your question seems to be broken by some software. either that on stackoverflow or the cut-and-paste process to put it here:
I saw:
I $P(GIH,,24)= S $P(GIH,,24)="C" S
What is the meaning of two S's in above MUMPS statement?
It is hard to figure out what you meant, since it would require hypothesizing where quotes might be and which ones could have been deleted by the transmission of the question.
First of all, let's do something we can guess is reasonable. $P is usually an abbreviation for the built-in (intrinsic) function $PIECE. an I standing alone is probably an IF command
and an S standing alone is probably a SET command. This runs into a problem with your example, because the format of a line of MUMPS code is COMMAND COMMAND-ARGUMENT.
Aside Note: I also just tried to put the text COMMAND-ARGUMENT in "angle brackets" ie: with a less-than character at the beginning of the word and a greater-than character at the end. The text COMMAND-ARGUMENT just disappeared. Which means that stackoverflow sees it as HTML markup. I notice there is a Code marker on the top of this edit window which may or may not help.
If we do the expansions to the code above, we get:
IF $PIECE(GIH,,24)= SET $PIECE(GIH,,24)="C" SET
When we expand the final S but it looks like a SET command, but without any set-argument.
Note, if this was in a Cache system, we might have an example of extra spaces allowed by Cache, which are not allowed in Standard MUMPS, ie the S may have been the right hand side of an equality operator in the IF command. This would only make sense if Cache also allowed the argument of the SET command to be in code without an actual SET command.
i.e.:
IF $PIECE(GIH,,24)=S $PIECE(GIH,,24)="C" SET
We still would have to deal with the two commas in a row for the $PIECE intrinsic function. Currently using two commas in a row to indicate a missing argument is only allowed in Programmer-written code, not when using built-in functions. So this might be a place where we can guess what you meant, or originally pasted in.
If we put in double-quotes we run into the problem that $PIECE command (which separates a string based on a delimiter) would have an quoted string of zero length given as its second argument. Which is just as erroneous as having an empty argument.
So if we hypothesize a quoted string that has angle brackets, we would get something this for your original line:
IF $PIECE(GIH,"<something>",24)="<something>" SET $PIECE(GIH,"<something>",24)="C" SET
Note: I just saw the Code marker allows use of grave accents to keep from assuming a line is HTML - which is good since grave accent is not a character used in MUMPS coding.
As has been mentioned on another reply, the SET-$PIECE-ARGUMENT form is used to change the data stored in a database at a particular delimited substring location.
So this code might be fine for guessing, but it has gone far afield of what you may or may not have done. So I'm stopping now until we get feedback that this is even close to what you wanted. As I said at the first, this is still not quite valid code.
This is pretty bizarre, but what I think is going on is:
I $P(GIH,<null>,24)=<null>
Calling $PIECE with the second argument null will replace the entire string with the value you're assigning, which, in this case, is also null. It looks like a convoluted way of clearing the value of GIH and permitting control to flow into the following SET statement. I seriously doubt that $PIECE sets the $T flag, though, which means that calling this as the condition for the IF operator probably isn't working the way you want it to.
S $P(GIH,,24)="C"
The next statement looks a lot like the first -- replace the entirety of GIH with "C".
S
I don't think the last SET is valid MUMPS.
Why this isn't written as follows is beyond me:
s GIH="C"
Hope that helps!
Maybe Intersystems Caché handles this syntax differently, but that code results in a syntax error when I try it in Caché. There may be other versions of MUMPS for which that is valid, but I don't think it is.
As other have pointed out this statement is not valid, It appears pieces are missing
But S is the SET command in Mumps
Here is what a statement like this might look like:
I $P(GIH,"^",24)="P" S $P(GIH,"^",24)="C" S UPDATEFLG=1
in this case GIH might look something like:
GIH=256^^^42^^^^Mike^^^^^^^^^^^^^^^^P^^^
which would make this evaluate to TRUE:
I $P(GIH,"^",24)="P"
so after:
S $P(GIH,"^",24)="C"
GIH will be:
GIH=256^^^42^^^^Mike^^^^^^^^^^^^^^^^C^^^
then it would set the variable UPDATEFLG=1
Hope this helps :-)
Is it a requirement of good TCL code? What would happen if we don't use the "unset" keyword in a script? Any ill-effects I should know about?
I'm inheriting some legacy code and the errors that come about due to "unset"-ing non-existent variables are driving me up the wall!
It's possible to determine whether a variable exists before using it, using the info exists command. Be sure that if you're not using unset, that you don't upset the logic of the program somewhere else.
There's no Tcl-specific reason to unset a variable, that is, it's not going to cause a memory leak or run out of variable handles or anything crazy like that. Using unset may be a defensive programming practice, because it prevents future use of a variable after it's no longer relevant. Without knowing more about the exact code you're working with, it's hard to give more detailed info.
In addition to the other responses, if your Tcl version is new enough, you can also use:
unset -nocomplain foo
That'll unset foo if it exists, but won't complain if it doesn't.
Depends on the system stats it may give "unable to allocate bytes" issue as and when your script is storing huge data into variables and arrays. it'll break once the cache or RAM is full saying "unable to allocate XXXXXXXX bytes".
Make sure you're not storing that much data into variables, otherwise do unset once the use is over for the respective datasets(variables)
For note as I don't seem able to comment on the "info exists" above;
I use this form often..
if { [info exists pie] && [$pie == "ThisIsWhatIWantInPie"]} {
puts "I found what I wanted in pie."
} else {
puts "Pie did not exist; but I still did not error,TCL's evaluation \
will see the conditional failed on the [info exists] and not \
continue onto the comparison."
}
In addition to the other responses, I want to add that, if you want to neglect the errors raising as a result of unsetting non-existent variable use 'catch'.
#!/bin/bash
catch {unset newVariable}