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 } } }