Is variable assignment within if conditions possible? - tcl

You know how in C and JavaScript variable assignments can take place within conditions, such as
if ( boolean || (val = func(args)) == case1 ) {
/* Perform A */
} else if ( val == case2) {
/* Perform B */
} ...
such that don't need to write another elseif to perform code A.
Can this be done in Tcl; and, if so, how?
It's not very important but I'd like to know just the same.
Thank you.

You can use set and other commands in an expr-ression, and set returns the newly assigned value, so...
set boolean true
proc func {} { return case2 }
if {$boolean && [set val [func]] eq "case1"} {
puts "case 1 found"
} elseif {$val eq "case2"} {
puts "case 2 found"
}

Related

Using Parameters to declare variable-sized Vec

I'm trying to have a variable-sized array based on a Module Paramete (example below). When the size PARAM is non-zero, the code works as intended.
class HWModule (PARAM : Int) extends Module{
val my_Vec = RegInit(Vec(Seq.fill(PARAM)(0.U(32.W))))
if (PARAM > 0){
for (i <- 0 until PARAM -1){
my_Vec(i) := i.U //Example Code
}
}
}
However, when I try to have PARAM = 0, it stops working. I've tried using Patter Matching (How do I write to a conditional output) to solve the problem, but I get the following error messages (and similar ones):
Equals does not take parameters
Expression does not convert to assignment because receiver is not assignable.
My goal is to be able to remove certain portions of code when PARAM = 0, while also allowing to variable-sized instantiation of Vecs, Regs, Wires, etc.
If anyone could point me to a good solution or information about it, I would appreciate it.
Thank you,
Miguel Silva
Maybe you can use Option like this :
val my_Vec_or_none = if(PARAM > 0) Some(RegInit(Vec(Seq.fill(PARAM))(0.U(32.W)))) else None
Then get register with get method :
if (PARAM > 0){
val my_Vec = my_Vec_or_none.get
for (i <- 0 until PARAM -1){
my_Vec(i) := i.U //Example Code
}
}
Also you can use indexed value directly (without intermediate val) :
val my_Vec = if(PARAM > 0) Some(RegInit(Vec(Seq.fill(PARAM))(0.U(32.W)))) else None
if (PARAM > 0){
for (i <- 0 until PARAM -1){
my_Vec.get(i) := i.U //Example Code
}
}
And use this variable in another part of the code.

PowerShell - "RETURN" in function returns values two times INSTEAD of just one

I was assuming that "return" in PowerShell function will return the value and exit the function, but instead of that I am getting the values for two times!!!!???
Please assist me.
I have a default value, I have logic for retreiving the real value (if exists) but instead I am getting two fules as output - but I do not want that! I need just one value.
Thank you in advance!!!
function GetTenantTagValue($TAG_SET_NAME) {
Write-Host("Tag Set Name:"+$TAG_SET_NAME)
$TAG_SET_VALUE = "N/A"
$TENANT_TAGS = "Customer Code/HEDGE"
$TENANT_TAGS | ForEach-Object {
$TAG_NAME = $_.split("/")[0]
$TAG_VALUE = $_.split("/")[1]
if ($TAG_NAME -eq $TAG_SET_NAME) {
# $TAG_SET_VALUE = $TAG_VALUE
Write-Host("Tag Value:"+$TAG_VALUE)
Write-Host("#########################")
return $TAG_VALUE
}
}
Write-Host("Tag Set Value:"+$TAG_SET_VALUE)
return $TAG_SET_VALUE
}
I invoke the function with:
GetTenantTagValue "Customer Code"

Reason my subroutine won't recurse

#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils 'uniq';
my %functiontable =();
$functiontable{foo} = \&foo;
sub iterate {
my ($function, $iterations, $argument) = #_;
return $argument unless 0 < $iterations;
return $argument unless $function = $functiontable{$function};
my #functioned = $function->($argument);
my #refunctioned = ();
for my $i (0 .. #functioned - 1) {
push #refunctioned, iterate ($function, ($iterations - 1), $functioned[$i]);
}
return uniq #refunctioned;
}
sub foo {
my ($argument) = #_;
my #list = ($argument, $argument.'.', $argument.',');
return #list;
}
my #results = iterate 'foo', 2, 'the';
print "#results";
This prints the the. the,, i.e. it doesn't iterate (recurse). I would expect it to print the the. the, the.. the., the,. the,,.
(I used Smart::Comments to check whether it enters iterate a second time, and it does, but it doesn't seem to do everything in the function.)
I can't figure out why. Can someone please help me figure out why, or propose a fix?
This line:
return $argument unless $function = $functiontable{$function};
doesn't make sense. In your subroutine iterate, $function is a string and $functiontable{$function} is a reference to a subroutine. I am not sure what the purpose of this is: is it to compare against the stored function? is it to use the function referenced by the name $function?
Assuming the latter it would make more sense to simply pass in a reference to a function when you call iterate:
sub iterate {
my ($function, $iterations, $argument) = #_;
return $argument unless 0 < $iterations;
my #functioned = $function->($argument);
my #refunctioned = ();
for my $i (0 .. #functioned - 1) {
push #refunctioned, iterate ($function, ($iterations - 1), $functioned[$i]);
}
return uniq #refunctioned;
}
my #results = iterate($functiontable{foo}, 2, 'the');
print "#results";
output:
the the. the, the.. the., the,. the,,
The problem is this line.
return $argument unless $function = $functiontable{$function};
The variable $function is being repurposed and overwritten from a string (the function name) to a code reference (the function to be executed). Later, it's passed into iterate which faithfully ignores it.
Two things would improve this code and avoid that sort of problem. First is to not repurpose variables, use two variables.
return $argument unless $function_ref = $functiontable{$function_name};
Now the mistake cannot happen. One strong indicator that you're repurposing a variable is that it changes type, like from a string to a code reference.
Note that I threw out $function entirely because it's too generic in this context. Is that the function's name or the function's reference? Neither one is obvious, so make it obvious.
Finally, iterate can be made more flexible by eliminating the function table entirely. Pass in the code reference directly. If you want a function table, write a wrapper.
sub select_iteration {
my($iteration_type, $iterations, $argument) = #_;
my $iteration_code = $iteration_types{$iteration_type};
return iterate($iteration_code, $iterations, $argument);
}
The first time your subroutine iterate is called it translates the subroutine name in $function from a name to a subroutine reference
So the first time iterate calls itself it is passing the subroutine reference, and the line
return $argument unless $function = $functiontable{$function};
will stringify the reference and attempt to find an element of the hash using a key something like CODE(0x23e0838)
Clearly that element doesn't exist, so your unless fails and $argument is returned immediately without continuing the recursion
Update
I would write something like this
#!/usr/bin/perl
use strict;
use warnings;
use 5.10.0;
my %functions = ( foo => \&foo );
sub iterate {
my ($func, $arg, $depth) = #_;
return $arg unless $depth;
map {iterate($func, $_, $depth - 1); } $functions{$func}->($arg);
}
sub foo {
my ($arg) = #_;
map "$arg$_", '', '.', ',';
}
my #results = iterate('foo', 'the', 2);
say "#results";
output
the the. the, the. the.. the., the, the,. the,,

what is the replacement of long nested if else construct?

I have a nested if else construct like below and i wanted to replace this
with the right type of programming statement.
if($provider[0][0]=='A' && $provider[1][0]=='B'){
return 'O';
}elseif($provider[0][0]=='B' && $provider[1][0]=='A'){
return 'O';
}elseif($provider[0][0] == 'A' && $provider[1][0] == '' ){
return 'A';
}elseif($provider[0][0] == 'B' && $provider[1][0] == '' ){
return 'B';
} else{
return 'Return nothing';
}
Not really avoiding nesting, but simplifying the reading:
<?php
function isOprovider($provider) {
return $provider[0][0]=='A' && $provider[1][0]=='B'
|| $provider[0][0]=='B' && $provider[1][0]=='A';
}
function isAprovider($provider) {
return $provider[0][0] == 'A' && $provider[1][0] == '';
}
function isBprovider($provider) {
return $provider[0][0] == 'B' && $provider[1][0] == '';
}
if (isOprovider($provider)) {
return '0';
} else if (isAprovider($provider)) {
return 'A';
} else if (isBprovider($provider)) {
return 'B';
} else {
return 'Return nothing';
}
One of the options to make it more readable-
if($provider[0][0]=='A') {
// other condition(s)
} else if($provider[0][0]=='B') {
// other condition(s)
} else {
// return nothing
}
You may try switch as well. In any case you would need nested conditions.
I would do something like this:
function IsCombinationOf($first, $second, $provider) {
return ($provider[0][0]==$first && $provider[1][0]==$second) ||
($provider[0][0]==$second && $provider[1][0]==$first);
}
if(IsCombinationOf('A', 'B', $provider)){
return 'O';
}
elseif(IsCombinationOf('', '', $provider)){
return 'Return Nothing';
}
elseif(IsCombinationOf('A', '', $provider)){
return 'A';
}
elseif(IsCombinationOf('B', '', $provider)){
return 'B';
}
I would replace most of this code with data and then use a loop to select the correct answer from the data. The idea here is to separate policy and implementation. The policy is: Given different combinations of providers, what do I return? The implementation is.... well, the implementation.
The example is in Ruby, but the idea applies to any language.
The data representing the policy might look like this:
PROVIDER_COMBOS = [
['A', 'B', 'O'],
['B', 'A', 'O'],
['A', '', 'A'],
['B', '', 'B'],
]
and the code that uses it might look like this:
def lookup_provider_combo(provider1, provider2)
PROVIDER_COMBOS.each do |key1, key2, result|
if provider1[0] == key1 && provider2[0] == key2
return result
end
end
return 'Return nothing'
end
Technically speaking that if..else statement is not nested. It is flat. Also, it is technically already at the state of minimum complexity. It is fairly simple code. It does "look" messy though. And the thing that makes it look messy is it's verbosity (don't confuse verbosity/messiness for complexity).
But you are right in complaining about verbosity. Verbose code, especially one with a lot of repeated bits, harms readibility. For the code in the example, one of the first obvious thing you can do to make it more readable is to factor out the array syntax:
p1 = $provider[0][0];
p2 = $provider[1][0];
if (p1 == 'A' && p2 == 'B') {
return 'O';
} elseif (p1 == 'B' && p2 == 'A') {
return 'O';
} elseif (p1 == 'A' && p2 == '' ) {
return 'A';
} elseif (p1 == 'B' && p2 == '' ) {
return 'B';
} else {
return 'Return nothing';
}
This alone removes cruft from the code making the logic clearer. There are other things you can do to remove more repeated bits from the code above to make it even clearer but they all boil down to what the code above does: basically a table of conditions and results.
In languages where the switch statement accept strings as input you can simply concatenate the two conditions into a single string as the switch condition:
switch (join([p1,p2],',')) {
'A,B' : return 'O'; break;
'B,A' : return 'O'; break;
'A,' : return 'A'; break;
'B,' : return 'B'; break;
default : return 'Return nothing'; break;
}
This makes it even more obvious that what you're doing is consulting a table. Alternatively you can achieve a similar layout using the ternary operator:
cond = join([p1,p2],',');
return cond == 'A,B' ? 'O' :
cond == 'B,A' ? 'O' :
cond == 'A,' ? 'A' :
cond == 'B,' ? 'B' :
'Return nothing';
Admittedly that still has the cond == bit repeated. But it is slightly easier to see the table compared to the original if..else statement.
In languages that has a dictionary/associative array/hash, you can simply encode the logic in a data structure and simply read that data structure:
conditions = {
'A' : {
'B' : 'O',
'' : 'A'
},
'B' : {
'A' : 'O',
'' : 'B'
}
}
result = conditions[p1][p2];
return result ? result : 'Return nothing';
Alternatively you can also use the following data structure:
conditions = {
'A,B' : 'O',
'B,A' : 'O',
'A,' : 'A',
'B,' : 'B'
}
result = conditions[join([p1,p2],',')];
return result ? result : 'Return nothing';
Keeping the conditional logic as pure data instead of code makes it even more obvious that what we're doing is looking up a table. Another advantage of keeping the conditions as pure data is that you can potentially create the data structure at runtime by reading it from a file (or from a socket over the internet). For example, the logic can potentially be encoded in a JSON or YAML formatted file and you can make the logic programmable.
As you can see, there are many ways to do this but it depends on what features are available in your programming language. They are all of the same complexity (and most compile to the same thing). The only difference is in terms of readability and maintainability.

Validate entry with BWidget's ComboBox

The BWidget ComboBox widget allows you to fill in an entry field with a value. I would like to enforce only specific characters in that field (e.g. only [a-z0-9]). For that purpose I would like to use Tcl/Tk's -validatecommand (or -vcmd for short), just as you do with the standard 'entry' widget:
proc ValidateMyEntry { value } {
# Check if it's alphanum string
if ![regexp {^[-a-zA-Z0-9]*$} $value] {
return 0
}
return 1
}
entry .my_entry -width 20 -textvariable myVar -validate key -vcmd {ValidateMyEntry %P}
It seems ComboBox does not support -validatecommand. What's the best work-around?
If you want to use a BWidget, you can try with -modifycmd or -postcommand.
Anyway I would suggest you to try the ttk::combobox with the -postcommand option.
As something that was possible but a bit cumbersome, I decided to use the old-style 'trace variable' function to enforce values in combobox.
Put the following statement after the ComboBox call:
trace variable myVar w forceAlphaNum
Elsewhere, you have to define the forceAlphaNum proc:
proc forceAlphaNum { name el op } {
if { $el == "" } {
set newname $name
set oldname ${name}_alphanum
} else {
set newname ${name}($el)
set oldname ${name}_alphanum($el)
}
global $newname
global $oldname
if { ![info exist $oldname] } {
set $oldname ""
}
# Check if it's alphanum string
if ![regexp {^[a-zA-Z0-9]*$} [set $newname]] {
set $newname [set $oldname]
bell; return
}
set $oldname [set $newname]
}