Why does Rakudo dd return Nil for a typed and assigned scalar? - raku

The below is a REPL session using Rakudo.
> my Int $x = 1
1
> dd $x
Int $x = 1
Nil
Why is there a Nil on the second line of the output of dd?

> sub mydd( $foo ) { dd $foo; "hello" }
&mydd
> mydd $x
1
hello
The Nil is the return value of dd, or lack thereof to be precise.

The REPL in Raku checks whether the code executed did any output to STDOUT. This is done with the assumption that if your code outputs something, that you would be interested in that, not the return value of the expression you just executed. So that is why:
> say 42
42
will only show 42 and not also show the return value of say (which happens to be True btw). It does not check STDERR. Check this with note:
> note 42
42
True
note is the same as say, but puts its output on STDERR instead of STDOUT. And the same applies to dd. So that's why you also get this with dd:
> dd 42
42
Nil
Except that the implementation of dd is returning Nil because it is intended as a debugging aid that should interfere as little as possible with its environment.

It's not "the output of dd" but rather output of the REPL based on the value returned by dd.
In more detail...
The R in REPL reads the line you enter (dd ...).
The E evaluates the line. It's dd, so it prints a line ending in a newline.
The P prints another line, also ending in a newline. If the evaluation in the prior step did not produce output on STDOUT, then the line this step produces includes the value returned by that evaluation.
(The L then loops around waiting for the next line of input.)
The first line you see after pressing Enter is output generated by dd.
The second line you see is output generated by the REPL.
By default, the content of the second line is the REPL's .gist of the value returned by the dd. The value dd returns is (always) Nil. So that's what you see.
(Liz has added a new environment variable since this SO was posted that lets users tell Rakudo what method to call; .gist is now merely the default.)

Related

Variable substitution within braces in Tcl

Correct me wherever I am wrong.
When we use the variables inside braces, the value won't be replaced during evaluation and simply passed on as an argument to the procedure/command. (Yes, some exception are there like expr {$x+$y}).
Consider the following scenarios,
Scenario 1
% set a 10
10
% if {$a==10} {puts "value is $a"}
value is 10
% if "$a==10" "puts \"value is $a\""
value is 10
Scenario 2
% proc x {} {
set c 10
uplevel {set val $c}
}
%
% proc y {} {
set c 10
uplevel "set val $c"
}
% x
can't read "c": no such variable
% y
10
% set val
10
%
In both of the scenarios, we can see that the variable substitution is performed on the body of the if loop (i.e. {puts "value is $a"}), whereas in the uplevel, it is not (i.e. {set val $c}), based on the current context.
I can see it as if like they might have access it via upvar kind of stuffs may be. But, why it has to be different among places ? Behind the scene, why it has to be designed in such this way ? Or is it just a conventional way how Tcl works?
Tcl always works exactly the same way with exactly one level of interpretation, though there are some cases where there is a second level because a command specifically requests it. The way it works is that stuff inside braces is never interpolated or checked for word boundaries (provided those braces start at the start of a “word”), stuff in double quotes is interpolated but not parsed for word boundaries (provided they start a word), and otherwise both interpolation and word boundary scanning are done (with the results of interpolation not scanned).
But some commands send the resulting word through again. For example:
eval {
puts "this is an example with your path: $env(PATH)"
}
The rule applies to the outer eval, but that concatenates its arguments and then sends the results into Tcl again. if does something similar with its body script except there's no concatenation, and instead there's conditional execution. proc also does the same, except it delays running the code until you call the procedure. The expr command is like eval, except that sends the script into the expression evaluation engine, which is really a separate little language. The if command also uses the expression engine (as do while and for). The expression language understands $var (and […]) as well.
So what happens if you do this?
set x [expr $x + $y]
Well, first we parse the first word out, set, then x, then with the third word we start a command substitution, which recursively enters the parser until the matching ] is found. With the inner expr, we first parse expr, then $x (reading the x variable), then +, then $y. Now the expr command is invoked with three arguments; it concatenates the values with spaces between them and sends the result of the concatenation into the expression engine. If you had x previously containing $ab and y containing [kaboom], the expression to evaluate will be actually:
$ab + [kaboom]
which will probably give you an error about a non-existing variable or command. On the other hand, if you did expr {$x + $y} with the braces, you'll get an addition applied to the contents of the two variables (still an error in this case, because neither looks like a number).
You're recommended to brace your expressions because then the expression that you write is the expression that will be evaluated. Otherwise, you can get all sorts of “unexpected” behaviours. Here's a mild example:
set x {12 + 34}
puts [expr $x]
set y {56 + 78}
puts [expr $y]
puts [expr $x * $y]
Remember, Tcl always works the same way. No special cases. Anything that looks like a special cases is just a command that implements a little language (often by calling recursively back into Tcl or the expression engine).
In addition to Donal Fellows's answer:
In scenario 2, in x the command uplevel {set val $c} is invoked, and fails because there is no such variable at the caller's level.
In y, the equivalent of uplevel {set val 10} is invoked (because the value of c is substituted when the command is interpreted). This script can be evaluated at the caller's level since it doesn't depend on any variables there. Instead, it creates the variable val at that level.
It has been designed this way because it gives the programmer more choices. If we want to avoid evaluation when a command is prepared for execution (knowing that the command we invoke may still evaluate our variables as it executes), we brace our arguments. If we want evaluation to happend during command preparation, we use double quotes (or no form of quoting).
Now try this:
% set c 30
30
% x
30
% y
10
If there is such a variable at the caller's level, x is a useful command for setting the variable val to the value of c, while y is a useful command for setting the variable val to the value encapsulated inside y.

How to pass functions as parameters in REBOL

I have attempted to pass a function as a parameter in the REBOL programming language, but I haven't figured out the correct syntax yet:
doSomething: func [a b] [
a b
a b
]
doSomething print "hello" {This should pass print as the first argument and "hello" as the second argument.}
This produces an error, since the print function is being called instead of being passed:
hello
*** ERROR
** Script error: doSomething does not allow unset! for its a argument
** Where: try do either either either -apply-
** Near: try load/all join %/users/try-REBOL/data/ system/script/args...
Is it possible to pass the print function as a parameter instead of calling the print function?
I've found the solution: I only need to add : before the name of the function that is being passed as a parameter.
Here, the :print function is being passed as a parameter instead of being invoked with "hello" as its argument:
doSomething: func [a b] [
a b
a b
]
doSomething :print "hello" {This should pass print as the first argument and "hello" as the second argument.}
You have discovered that by the nature of the system, when the interpreter comes across a WORD! symbol type which has been bound to a function, it will invoke the function by default. The default interpreter seeing a GET-WORD! symbol type, on the other hand, suppresses invocation and just returns the value the word is bound to.
The evaluator logic is actually rather straightforward for how it reacts when it sees a certain symbol type. Another way of suppressing invocation is the single quote, which will give you a LIT-WORD! symbol... but these become evaluated as the corresponding WORD! when it sees them:
>> some-word: 'print
>> type? some-word
== word!
In fact, the behavior of a GET-WORD! when the evaluator sees it is equivalent to using the GET function with a WORD!
doSomething: func [a b] [
a b
a b
]
doSomething get 'print "hello" {Message}
The interpreter sees the LIT-WORD! 'print and evaluates that into the WORD! for print, which is then passed to GET, which gives you a FUNCTION! back.
Simplicity of the interpreter logic is why you get things like:
>> a: b: c: 10 print [a b c]
10 10 10
Due to the nature of how it handles a SET-WORD! symbol followed by complete expressions. That yields also the following code printing out 20:
if 10 < a: 20 [
print a
]
Other languages achieve such features with specialized constructs (like multiple initialization, etc.) But Rebol's logic is simpler.
Just wanted to elaborate a bit to help explain what you were looking at. My answer to this other question might provide some more insight into the edge cases, historical and future: "When I use error? and try, err need a value"

While debugging, how can I jump to a function, execute it and return from where I left off?

Say function A consists of 10 lines. I set a breakpoint at line 5, when I hit it, I want to Execute function B, before returning to A. On return, Id like the flow to continue at line 5.
The lldb expr command evaluates a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.
Examples:
expr -- functionB(17)
expr -- [self methodB]
Sometimes it is necessary to specify the return value explicitly, for example
expr -- (void)functionB(17)
If the function returns an Objective-C object then you can use po as an alias
for expression -O --, in that case lldb prints the description of the return value.
You can also add the debugger command as an "Action" to the breakpoint,
to have it executed automatically when the breakpoint is hit:

Getting input from the user in Lua

How can I get an input from user in Lua (like scanf in C)?
For example, the program ask user his name, then he writes his name, then the program will output his name.
Use io.read() Beware that the function can be customised with different parameters. Here are some examples.
s = io.read("*n") -- read a number
s = io.read("*l") -- read a line (default when no parameter is given)
s = io.read("*a") -- read the complete stdin
s = io.read(7) -- read 7 characters from stdin
x,y = io.read(7,12) -- read 7 and 12 characters from stdin and assign them to x and y
a,b = io.read("*n","*n") -- read two numbers and assign them to a and b
The simplest input can be retrieved using io.read(). This will read a single line from the standard input (usually the keyboard, but can be redirected e.g. from file).
You can use it like this:
io.write('Hello, what is your name? ')
local name = io.read()
io.write('Nice to meet you, ', name, '!\n')
io.read() is just a shortcut for io.input():read(), similarly io.write() is a shortcut to io.output():write(). See the API for read() here.
Notice that io.write() will not auto-terminate your line like print() does.

Reading comment lines correctly in an input file using Fortran 90

It is my understanding that Fortran, when reading data from file, will skip lines starting with and asterisk (*) assuming that they are a comment. Well, I seem to be having a problem with achieving this behavior with a very simple program I created. This is my simple Fortran program:
1 program test
2
3 integer dat1
4
5 open(unit=1,file="file.inp")
6
7 read(1,*) dat1
8
9
10 end program test
This is "file.inp":
1 *Hello
2 1
I built my simple program with
gfortran -g -o test test.f90
When I run, I get the error:
At line 7 of file test.f90 (unit = 1, file = 'file.inp')
Fortran runtime error: Bad integer for item 1 in list input
When I run the input file with the comment line deleted, i.e.:
1 1
The code runs fine. So it seems to be a problem with Fortran correctly interpreting that comment line. It must be something exceedingly simple I'm missing here, but I can't turn up anything on google.
Fortran doesn't automatically skip comments lines in input files. You can do this easily enough by first reading the line into a string, checking the first character for your comment symbol or search the string for that symbol, then if the line is not a comment, doing an "internal read" of the string to obtain the numeric value.
Something like:
use, intrinsic :: iso_fortran_env
character (len=200) :: line
integer :: dat1, RetCode
read_loop: do
read (1, '(A)', isostat=RetCode) line
if ( RetCode == iostat_end) exit ReadLoop
if ( RetCode /= 0 ) then
... read error
exit read_loop
end if
if ( index (line, "*") /= 0 ) cycle read_loop
read (line, *) dat1
end do read_loop
Fortran does not ignore anything by default, unless you are using namelists and in that case comments start with an exclamation mark.
I found the use of the backspace statement to be a lot more intuitive than the proposed solutions. The following subroutine skips the line when a comment character, "#" is encountered at the beginning of the line.
subroutine skip_comments(fileUnit)
integer, intent(in) :: fileUnit
character(len=1) :: firstChar
firstChar = '#'
do while (firstChar .eq. '#')
read(fileUnit, '(A)') firstChar
enddo
backspace(fileUnit)
end subroutine skip_comments
This subroutine may be used in programs before the read statement like so:
open(unit=10, file=filename)
call skip_comments(10)
read(10, *) a, b, c
call skip_comments(10)
read(10, *) d, e
close(10)
Limitations for the above implementation:
It will not work if the comment is placed between the values of a variable spanning multiple lines, say an array.
It is very inefficient for large input files since the entire file is re-read from the beginning till the previous character when the backspace statement is encountered.
Can only be used for sequential access files, i.e. typical ASCII text files. Files opened with the direct or append access types will not work.
However, I find it a perfect fit for short files used for providing user-parameters.