html lang="en" {
head { m4_include(head.gsp) }
body {
header {
div {
h1 {-So Much Value}
m4_include(nav.gsp)
}
figure .quote {
blockquote {
p {=
Complexity is a backdoor and can be misinterpreted as
sophistication.
}
}
figcaption {-asvln.com}
}
}
main {
h2 #value {-Values}
p {-
As covered in @a href="/blog/new-sh" {-my last post}, I’m working on
Andy, my personal shell. One of the pretty interesting features of Andy
I think is the way that @em{-values} are handled. In the conventional
shell, you can think of a value as a string. In @code{-echo foo}, both
‘echo’ and ‘foo’ can be thought of as values. Values aren’t just
string-literals though, a Bash process-redirection (@code{-<(cmd)}) is
also a value; typically one that looks like ‘/dev/fd/N’.
}
p {-
In Andy this mostly holds, with one very important difference: values
are not strings — they’re lists of strings. While the string-literal
@code{-"foo"} might be a string list of length 1, the
process-redirection of @code{-<>{cmd\}} is a list of 2 strings — a path
to a file you can read from, and a path to a file you can write to.
}
p {-
This is an important distinction to make because of the fact that
value-concatenation goes from a simple string-concatenation to a
cartesian product of the left- and right values:
}
figure {
pre {= m4_fmt_code(cartesian.an.gsp) }
}
p {-
This is not just constrainted to literals of course, process
substitutions are also values, so appending each line of a processes
output with a closing-angle-bracket becomes trivial:
}
figure {
pre {= m4_fmt_code(angle-bracket.an.gsp) }
}
p {-
Of course you can also append the closing-angle-bracket using
@code{-printf} itself, but it’s just an example after all.
}
h2 #dynamic {-Dynamic Code}
p {-
What makes Andy different is not just the behavior of values, but where
you can use them. In most shells, various syntactic elements are not
expanded in the same way that regular values are. The following example
results in an error because the function name @code{-$foo} doesn’t get
expanded into @code{-bar}:
}
figure {
pre {= m4_fmt_code(posix-fail.sh.gsp) }
}
p {-
Andy doesn’t give a fuck though, it lets you do this if you really want
to:
}
figure {
pre {= m4_fmt_code(dynamic-func.an.gsp) }
}
p {-
Now you might think that this is really retarded — especially if you’re
a Rust developer — and you know what? I did too! But you know what the
beauty of recreational programming is? It doesn’t @code{-have} to be
good — and once you learn to ignore the low-value morons that will
see you experimenting with new ideas and call it garbage — you can start
to actually develop some pretty neat solutions to problems.
}
p {-
For example, Andy like all shells implements support for signal
handling. In the POSIX shell this is done via the ‘trap’ builtin
function:
}
figure {
pre {= m4_fmt_code(trap.sh.gsp) }
}
p {-
Now personally, I really don’t like @code{-trap}. Having to write your
signal handling code in string is just not very ergonomic. You
@em{-can} put your code in a function that you then call in your signal
handler, but I think Andy can do better. The way you handle a signal in
Andy is to simply define a function of the name ‘sigX’ where ‘X’ is the
name of the signal. If you want to write a handler for SIGINT, you
simply define the ‘sigint’ function!
}
p {-
What if we want to handle multiple signals though? In the above
example, we deleted some temporary files on SIGQUIT and also on the
special SIGEXIT (a fake signal that signifies that the process is
exiting). Well the naïve solution is to simply define a handler
function that you call from your handlers:
}
figure {
pre .sh {= m4_fmt_code(naïve.an.gsp) }
}
p {-
But wait… remember how we can dynamically define functions? What if we
just… dynamically define our signal handlers:
}
figure {
pre .sh {= m4_fmt_code(smart.an.gsp) }
}
p {-
Personally, I think that’s pretty neat, and I like it! Of course some
Haskell developer that’s never @em{-actually} written any working
software will probably be sending me an angry email right about now
about how this is unsafe code and blah blah, but I don’t care.
}
p {-
I suppose while this post is primarily about just showing off some of
Andy’s behavior, I also want to make the point that it’s always a good
idea to just try new ideas, no matter how contrary they are to ‘best
practices’ and Rust developers. Don’t waste your time worrying about
what other people think about what you make; I used to do that, and it’s
not great. Just make shit, even if it’s weird. You might just
accidentally add a cool new feature you actually kind of like.
}
}
hr{}
footer { m4_footer }
}
}