Why Sponsor Oil? | source | all docs for version 0.14.2 | all versions | oilshell.org
Warning: Work in progress! Leave feedback on Zulip or Github if you'd like this doc to be updated.
Procs are shell like-functions, but they can have declared parameters, and lack dynamic scope.
proc p(name, age) {
echo "$name is $age years old"
}
p alice 42 # => alice is 42 years old
Blocks are fragments of code within { }
that can be passed to builtins (and
eventually procs):
cd /tmp {
echo $PWD # prints /tmp
}
echo $PWD # prints original dir
Shell-like open procs that accept arbitrary numbers of arguments:
proc open {
write 'args are' @ARGV
}
# All valid:
open
open 1
open 1 2
Stricter closed procs:
proc closed(x) {
write 'arg is' $x
}
closed # runtime error: missing argument
closed 1 # valid
closed 1 2 # runtime error: too many arguments
TODO:
''
to null
for string argument defaults.@
is "splice" at the call site. Or also "rest" parameters.:
for ref params&
for blocks?
These forms work:
cd / {
echo $PWD
}
cd / { echo $PWD }
cd / { echo $PWD }; cd / { echo $PWD }
These are syntax errors:
a=1 { echo bad }; # assignments can't take blocks
>out.txt { echo bad }; # bare redirects can't take blocks
break { echo bad }; # control flow can't take blocks
Runtime error:
local a=1 { echo bad }; # assignment builtins can't take blocks
Caveat: Blocks Are Space Sensitive
cd {a,b} # brace substitution
cd { a,b } # tries to run command 'a,b', which probably doesn't exist
Quoting of { }
obeys the normal rules:
echo 'literal braces not a block' \{ \}
echo 'literal braces not a block' '{' '}'
TODO: This section has to be implemented and tested.
yield
keyword?)proc p(&block) {
echo '>'
$block # call it?
# or maybe just 'block' -- it's a new word in the "proc" namespace?
echo '<'
}
# Invoke it
p {
echo 'hello'
}
# Output:
# >
# hello
# <
How to get the value?
var namespace = evalblock('name', 1+2, up=1)
# _result is set if there was a return statement!
# namespace has all vars except those prefixed with _
var result = namespace->_result
TODO: Subinterpreters?
Generally, errors occur inside blocks, not outside:
cd /tmp {
cp myfile /bad # error happens here
echo 'done'
} # not here
break
and continue
are disallowed inside blocks.return
(not the enclosing function).exit
is identical: it exits the program.Can block can set vars in enclosing scope?
setref('name', 1+2, up=1)
Evaluates to JSON (like YAML and TOML):
server foo {
port = 80
}
And can also be serialized as command line flags.
Replaces anti-patterns:
BEGIN {
end
}
when x {
}
rule foo.c : foo.bar {
cc -o out @srcs
}
Probably use a block format. Compare with Python's optparse.o
See issue.
Haven't decided on this yet.
check {
}
In addition to shell-like procs, Oil also has Python-like functions:
var x = len(ARGV) + 1
For now, we only have a few builtin functions like len()
.
There are two kinds of composition / code units in Oil:
argv
array and returning exit code. I think of proc
as procedure or
process.
procs are called with a "command line":
my-proc arg1 arg2 arg3
funcs are called with Python/JS-like Oil expressions:
var x = my_func(42, 'foo')
_ my_func(42, 'foo') # throw away the return value.
This may be legal:
my-proc (42, 'foo') # note space
This is NOT legal:
my_func(42, 'foo') # it's illegal whether there's a space or not
That is, procs can call funcs, but funcs won't be able to call procs (except
for some limited cases like log
and die
).
People may tend to prefer funcs because they're more familiar. But shell composition with proc is very powerful!
They have at least two kinds of composition that functions don't have. See #shell-the-good-parts on Bernstein chaining and "point-free" pipelines.
Here are some complicated examples from the tests. It's not representative of what real code looks like, but it shows all the features.
proc:
proc name-with-hyphen (x, y, @names) {
echo $x $y
echo names: @names
}
name-with-hyphen a b c
procs:
Examples:
kebab-case (1, 2, 3)
kebab-case {
const block = 'literal'
}
HayBlock {
const block = 'literal'
}
funcs: Python- and JavaScript, like
Examples:
var x = strip(y)
= strip(y) # pretty print
_ strip(y) # not useful
echo $[strip(y)]
write -- @[split(x)]
write -- @[glob(x)] # it's possible for this to fail
# arguments to procs are expressions!
append (x, strip(y))