Post Thanksgiving

Apologies for the lack of posts, I’ll add them when I can but the mix of a 1 year old, full time job, and research makes making them nearly impossible. A lot has been going on, and I wanted to make a post-thanksgiving post. Namely I want to talk about work.

Currently I’m a level 4 software engineer at Google. It’s not bad work, it can be entertaining and I even get to program in Lisp. If I had to write Java that would be one thing, but Lisp is truly an enjoyable language that deserves much more attention then it’s getting. That, and the pay, make it basically impossible to leave and just work on math. Adding to that the near impossibility of finding a decent academic job makes it the proposition even crazier.

In my spare time, besides spending time with my little one, I’m a PhD student in Operator Algebra’s/ Quantum Information Theory. I’ve been doing way to much reading of C*-Algebras by Example, time that would probably be mostly better spent doing research. That being said, I need a better background in C*-Algebras and this book is wonderful. I feel like I have a decent understanding of AF Algebras!

This seems great, the issue is it’s really hard to do both research and work at the same time. I spend 10-6:30 at work, 6:45-9 with Lyra, and the rest of the time trying to learn math (and cleaning, and a little bit of relaxing). It leaves little time to focus on what I’m passionate about.

I hope this explains the lack of blog posts, there will be some in the future, just sparser then in the past.

Until then, I leave you with:

img_20191118_092533

P.S. I hope to have a video detailing the GNS Construction and the extra part of the proof that every C* algebra is *-isomorphic to a Concrete C* Algebra. It’s a really nice theorem that everyone should see.

P.P.S. You should check out my wife’s thesis here.

Class VS Struct in Lisp Revisited

Last time we tried to test Class VS Struct, and I got several comments on ways I could improve the tests. We will be looking at performance improvements that can be made for defstruct. We will be running on an Intel Core i5 Pixelbook using SBCL (except where CCL is specified).

You can find the code:

https://github.com/Slids/lisp-perf-test/blob/master/class-v-struct-boa.lisp


Random Takes Time

Starting, random adds quite a bit of time. It used enough time to massively obfuscate the time things were taking. We can see how much time random is taking

(time (dotimes (i 1000000000) (random 100)))

Evaluation took:
31.172 seconds of real time
31.168020 seconds of total run time (31.168000 user, 0.000020 system)
99.99% CPU
50,123,948,880 processor cycles
0 bytes consed


Argument Constructors are Bad

The next problem is using the default struct constructor instead of using a a constructor with positional arguments. I say, why should this by slower? They say, it’s a bug. We see:

(defstruct (simple-struct
             (:constructor make-simple-struct
               (slot-1 slot-2 slot-3)))
             (slot-1)
             (slot-2)
             (slot-3))
(time (dotimes (i 1000000000)
        (make-simple-struct 1 2 3)))

Evaluation took:
9.602 seconds of real time
9.714198 seconds of total run time (9.268526 user, 0.445672 system)
[ Run times consist of 2.013 seconds GC time, and 7.702 seconds non-GC time. ]
101.17% CPU
15,438,933,331 processor cycles
32,000,006,848 bytes consed

(defstruct simple-struct-2
  (slot-1)
  (slot-2)
  (slot-3))
(time (dotimes (i 1000000000)
        (make-simple-struct-2 :slot-1 1
                              :slot-2 2
                              :slot-3 3)))

Evaluation took:
20.735 seconds of real time
20.927129 seconds of total run time (20.470935 user, 0.456194 system)
[ Run times consist of 2.453 seconds GC time, and 18.475 seconds non-GC time. ]
100.93% CPU
33,340,558,882 processor cycles
32,000,007,568 bytes consed

So we get pretty large savings making a boa-constructor!

We can do more and declaim the constructor inline:

(declaim (inline make-simple-struct-3))
(defstruct (simple-struct-3
             (:constructor make-simple-struct-3
               (slot-1 slot-2 slot-3)))
             (slot-1)
             (slot-2)
             (slot-3))
(time (dotimes (i 1000000000)
        (make-simple-struct-3 1 2 3)))

Evaluation took:
0.363 seconds of real time
0.362868 seconds of total run time (0.362868 user, 0.000000 system)
100.00% CPU
583,539,405 processor cycles
0 bytes consed

We were able to stack-allocate the struct leading to quite the savings and no garbage collection. I wouldn’t suggest this very often but it’s an impressive change.


Rerunning Instantiation Tests

I will re-run the instantiation test with our defstruct having the boa-constructor and not using random.

SBCL

CCL.png

Note: For CCL the struct instantiation test took: 0.238095 seconds. Why was class so terrible? CCL folks?

For there information the output was:

(LOOP FOR I FROM 1 TO RUN-TIMES DO (MAKE-INSTANCE ‘SIMPLE-CLASS :SLOT-1 I :SLOT-2 I :SLOT-3 I))
took 33,453,955 microseconds (33.453957 seconds) to run.
68,225 microseconds ( 0.068225 seconds, 0.20%) of which was spent in GC.
During that period, and with 4 available CPU cores,
33,421,986 microseconds (33.421986 seconds) were spent in user mode
66,531 microseconds ( 0.066531 seconds) were spent in system mode
800,000,528 bytes of memory allocated.
303 minor page faults, 0 major page faults, 0 swaps.

Thanks

I would like to thank @dougk (Google) and @stassats (Reddit account) for the comments and suggestions!


As usual I like to end with a picture:

img_20190909_174425

Class VS Struct in Lisp

It is taken as Gospel that classes are less performant then structs in Common Lisp. This is told to me by one of the main maintainers of SBCL, so for the most part I believe it. This being said, I wanted to see for myself, so I made a simple script and did my own tests. The tests were run in both Clozure Common Lisp (CCL) and Steel Bank Common Lisp (SBCL) on my Lenova Carbon laptop.


Note: These test are very simple, probably don’t represent usual use of class and structs in user code, and I know a lot of people will make a lot of comments on this. That being said, I just wanted to run some basic checks.

All of the code can be found:

https://github.com/Slids/lisp-perf-test/blob/master/class-v-struct.lisp

I will happily take pull requests.


Test slot accessing and setting:

I made a class and a struct that contains 3 un-typed slots. Outside of timing I instantiated the class and the struct. Then with the Lisp time function  set a random slot for a class or struct a random int:

(defun set-random-struct (my-struct)
     (ecase (random 3)
        (0 (setf (simple-struct-slot-1 my-struct)
          (random 100)))
        (1 (setf (simple-struct-slot-2 my-struct)
          (random 100)))
        (2 (setf (simple-struct-slot-3 my-struct)
          (random 100)))))

I ran this 1,000,000,000 for both the class and the struct.I ran this 1,000,000,000 for both the class and the struct.

Set Test (1)

We see structs are in fact faster, though in SBCL the difference is (nearly) negligible. There was no consing so no memory usage.


Test instantiation:

Next we want to test the memory and time of instantiating a set vs a class. For this we just instantiated either a class of a struct setting each slot to a random int:

(make-instance 'simple-class
     :slot-1 (random 10)
     :slot-2 (random 10)
     :slot-3 (random 10))

We ran this (and likewise for struct) 10,000,000 times:

Instantiate Time

Class is a little faster then struct.

Instantiate Consing (1).png

Consing for classes was much worse then structs.


Test Both:

Next we try both instantiating once then setting 100000 times, in 1000 loops for both class and struct:

Instantiate and Set 

So time wise in SBCL they perform almost the same, but for CCL classes are quite a bit slower.

Instantiate and Set Consing

Here we see structs outperform classes hands down.


We see that struct generally performs better. For most cases, you’ll probably be okay either way but for performance struct is better.

And finally:

img_20190824_145150-1

Note: After talking to Dougk I found out I was previously testing the print functions in the instantiate test for Struct and Class. The document has been updated

Macros in Lisp

Note: This post had to be update, WordPress seemed to mangle some of my writing making it less then readable (deleted some text and merged a lisp macro and a c++ function).

Whats the special sauce of Lisp? Macros! And Code as Data etc…

What is a macro? It’s a way to write code that generates more code, or it’s a way to improve/increase the syntax of your language. This confused me for quite a while, so lets go with an example.

Recently, I was writing code that contacts a database in C++. First it creates a connection to the database, runs a query on said database, does some processing collected to the database (the database sends back only a row at a time), and then closes the connection. Since my query is slow (the table is HUGE) it frequently times out giving a retry-able error. The code looks like:

void QueryDatabaseWithWork() {
     DatabaseConnection conn;
     RunQuery(&conn);
     DoWork(conn.Result());
     assert(conn.Finish() == 0);
}

So we create a database connection, run a query, do some work with the returned rows and then call Finish(). Finish() will return either 0 for success, 1 for retry-able error or -1 for non-retry-able errors. So you tell me just wrap this in a loop. (Note wordpress keeps undoing changes to the below code…)

void QueryDatabaseWithWorkRetry() {
     char status = 1;
     for(int attempts = 0;
         attempts <= 10 && status == 1;
         attempts++) {
         if (attempts > 0) {
           sys.sleep(attempts * Milliseconds(10));
           std::cout << "On retry: " << attempts;
         }
       RunQuery(&conn);
       DoWork(conn.Result());
       status = conn.Finish();
     }
     assert(status == 0);
}

This code is fine… I even submitted a CL that looks suspiciously like this. The issue is you must do this EVERY place you have a a query with a bit of work. Of course you could parameterise the query and put the work in a lambda, a runnable or another construct, but this separates your query from your work, and causes a level of indirection that makes code hard to read.

Instead we can extend our language to create a control flow syntax (like while or for) that will give us retries.

(defmacro retry-query (status &body body)
  `(loop :for attempts from 0 to 10
         :while (= status 1)
         :do
       (when (> attempts 0)
         (sleep (* 10 ,attempts))
         (format nil "On attempt ~a" (+ attempts 1)))
       ,@body))

Note: Before we discuss this macro note this is not “production” grade, the macro has variable capture and there are plenty of arguments that should be modifiable, but that would make our example more complex then it should be.


What this will do is allow the user to specify a “status” variable that, if equals 1, will retry the body. We see in the loop body that it will retry up to 10 time and log after every failure. We have also added a back-off in the form of a sleep as before.

Now lets use this macro:

(defun query-database ()
  (let ((conn nil))
    (retry-query
     status
     (setf status (run-query 'my-query)))))

First, we require the user to update status. This makes this macro more useful, as long as we set status to 1 for retry anything can have a retry-able back off, not just this kind of query. Another option is to require body to return the status (retry-able or not) and put the setf in the macro. I’ll give this in the bottom of the page.

I said macros generate code. We used the retry-query macro to allow us to get retries for our code, but what lisp will do is expand

(retry-query
status
(setf status (run-query 'my-query)))

So after macro-expansion Lisp will compile:

(defun query-database ()
  (let ((conn nil))
    (LOOP :FOR ATTEMPTS FROM 0 TO 10
          :WHILE (= STATUS 1)
          :DO
        (WHEN (> ATTEMPTS 0)
          (SLEEP (* 10 ATTEMPTS))
          (FORMAT NIL "On attempt ~a" (+ ATTEMPTS 1)))
        (SETF STATUS (RUN-QUERY 'MY-QUERY)))))

Which is much like the C++ code from above. Instead of having to deal with worrying about abstract classes or interfaces to pass through functionality, or lambda function for dealing with work, we just use our retry-query macro.


I know it’s hard to understand the use of macros for new Lispers, or non-Lispers. I hope I’ve made you a little interested!

I leave you with Lyra and Stitch.

img_20190809_205742


P.S.

Here’s a macro that at least removes variable capture and adds at least minimal flexibility:

(defmacro retry-query ((status &key
                               (log-stream nil)
                               (num-retries 10))
                       &body body)
  (let ((attempts (gensym "attempts")))
    `(loop :for ,attempts from 0 to ,num-retries
           :while  (= ,status 1)
           :do
        (when (> ,attempts 0)
          (sleep (* 10 ,attempts))
          (format ,log-stream "On attempt ~a"
                  (+ ,attempts 1)))
           ,@body)))

or if you know that your body will return 1 for retriable:

(defmacro retry-query ((&key (log-stream nil) (num-retries 10))
                       &body body)
  (let ((attempts (gensym "attempts"))
        (status (gensym "status")))
    `(loop :for ,attempts from 0 to ,num-retries
           :while (= ,status 1)
           :do
         (when (> ,attempts 0)
           (sleep (* 10 ,attempts))
           (format ,log-stream "On attempt ~a"
                   (+ ,attempts 1)))
         (setf ,status ,@body))))

UPDATE: You can also write macros in a language with C-Style syntax in Dylan (example given by @cgay):

define macro with-retry
  { with-retry (#key ?log-stream:expression,
                      ?num-retries:expression = 10)
               ?:body
    end
  }
  => { block (exit)
       for (attempt from 0 to ?num-retries)
         if (attempt > 0)
           sleep(attempt * 10);
           format(?log-stream | *standard-output*, "Attempt %d",
                attempt);
         end;
         if (?body ~= -1)
           exit()
         end
       end
       end block
     }
end macro with-retry;

Here’s Some Pointers

Here’s a pointer: pointers suck!

pointers
XKCD: https://xkcd.com/138/

First, no they don’t, but whats a pointer? For those who are still reading this and are not programmers, pointers are variables that contain a memory address. Say you have

void foo() {
int x = 5;
int* y = &amp;x; // *y == x
cout << y; // print address of x
cout << *y; // print 5 (ie x)
cout << x; // print 5 (ie x)
}

 

Now x is a variable that stores the value 5, and &x says “heres where x is stored”. So saying y = &x tells us that y contains the address of x. In fact, you could read int* as the memory address of an int.

Then *y says, go to the address y is pointing to. What if we did *x? We’d get an error. This being said, &y is still valid, it’s the memory address of the memory address of an int, or int**.  Finally, “cout << x” just says display the value of x to the screen.

If your not a programmer and you don’t understand that’s okay. If you’re a programmer complaining about me eliding certain facts, my apologies.

Now, we if I had a function

void foo(int* y) {
cout << *y;
}
void bar() {
int* z;
foo(z);
}

We would expect all to be okay, we print the int that y is pointer to. But what would that value be? Well,  int* z is saying z will be a pointer to an int, we don’t know where that pointer is, but we will set it soon.

A memory address is an integer from 0 to 2^32 -1 or 2^64 – 1 depending on your processor, and a memory address is stored as an integer. Lets say your processor is 64 bit so 0 to (2^64)-1. So y will be a value from 0 to 2^64 – 1, but its unlikely that this place in memory will contain an integer. Most likely, int* z will set the value z to 0, so “cout << z” should just return zero, but we can’t be sure. Then what will cout << *y; return? It will probably crash whatever program your running.

img_20190707_203609

So why do we use them? They make our code faster. If z was a pointer to 5000 integers:

void foo1(set y) { cout << *y; }
void foo2(set* y) { cout << *y; }
void bar() {
set z = {...}; // z sets 5000 ints
foo1(z);
foo2(&z);
}

Then foo1 has to copy 5000 integers where foo2 just uses those integers!

That being said, this difference has caused a lot of the bugs you’ve heard of, and wasted hours of my life!

Hope you learned something!

img_20190706_131409

For My Daughters First Independence Day

To Lyra,

Today was your first fourth of July, there were some fireworks, though we went home before the big event. There was some junk food, though all you had was sweet potato. You seem to enjoy walking around but the fireworks just confused you, and the national anthem seemed the same as every other song.

You were born into a divided nation. It’s something we can see in every family, especially ours. My parents are Trump supporters, and my co-workers are anti-Trump. It’s hard to understand the divide, why the sides are so against each-other, hopefully this will sort itself out before your old enough to care.

The last fourth of July you were smaller, still in mama. We told you stories like The Little Taxi That Hurried, which made you move a lot. We watched the fireworks together, though you never knew.

What really made me think, was what will you think of this holiday. As you grow up will you care about the US National Anthem? The Chinese National Anthem? Will you believe in Independence Day, or 国庆节? I hope for both.

I don’t know what the future holds my little one, but 我爱你.

Dada

download_20190704_221906

 

Utilities File

A continually contention in a lot of software development is whether or not to have a utilities file. Some people say that any “utility” function you may want to write should be place-able in a file that currently exists, hopefull it naturally fits around say currency.lisp or fish.lisp. On the other hand, other people say it’s natural, maybe you have a natural dislike of C#’s library for making HTTP calls, and you have a nice wrapper, as well as some string stuff etc. Maybe you feel this naturally belong in a utility file, or maybe a utility folder and your HTTP wrapper can be in a nice file labeled http-wrapper.cs.

Note: I believe in polyglot development.

Truthfully, such a requirement is probably a larger statement on the standard libraries of your language. For a long time C++ has terrible string libraries, thankfully now we have absl. On the other hand the http libraries in C# are meant to be fairly general, and a lot of time your calls are more specific, so often you wish to specialize and it would make little sense to put such specialization into the standard language, so it makes sense to make a nice class yourself.

This gets even more common when you start working on Common Lisp (who’s standard is over 20 years old). The macro system makes it easy to add on to the language, and developers often use their own macro-extensions, sometimes elevating it to a new language, it’s been called a language with a worldwide developer community of 1. If every user is creating their own set of libraries for usually use, maybe it’s time to update the spec.

I think a utility file is not the best idea. As I said above you should at least have a mapping of things your functions will be used around, though I think there are cases when a utility folder is useful. When I was a new developer I was wary of making new files, honestly there cheap and the directory structure can help you find the code you want, utilities/http.cs is much easier to find then


utilities.cs;

Class http-wrapper {

// Your code here.

}


But I don’t want to put my http.cs file inside of foo/bar/main-code/ , it just doesn’t belong there.

Also, in case your listening, test-data.lisp and testdata.lisp are both perfectly fine.

Note: Sony for any war this causes…

Finally:

img_20190630_105152

Mothers Day Post

As this is mothers day, I thought I’d talk about taking care of a little one. My wife is celebrating her first mothers day, on top of that shes trying to take care of Lyra (I’m trying to help), and dealing with end of classes.

img_20190512_111220


Side note: End of classes means students who don’t like their grades, and want some kind of special treatment.


My wife chose teaching in part for the ability to have a very flexible work schedule. You have to be in class, but you can make your teaching plans and do your grading wherever you want. What most teachers-to-be don’t realize is there’s a lot more to the trade, and its busy. She’s been a lecturer in several schools in multiple countries, so she know this, but your still busier then you would imagine.

On the other hand, this gives her the ability to watch Lyra for most of the day. When Lyra is sleeping she is usually grading, or checking her email, etc.

So, when do I watch Lyra. I work (Typically) from 9:30 – 6:30. So Lyra will wake up at 8 (Wenwen has starting to call her an alarm clock it’s so deterministic). She will check on Lyra and I will groggily wake up, then I will watch Lyra until shes finished whatever she’s doing in the morning, and I will go to work.

img_20190227_194749

When I get home I will take care of Lyra while Wenwen cooks. We will eat with Lyra in the high chair, and I will watch Lyra until 8:45. Then Lyra goes to bed (Wenwen will feed the little one to sleep). The weekends, while Lyra is awake, are generally devoted to her.


Take-Aways:

  • Working is far less tiring then taking care of a 7 month old. They want to play, but with a new toy every few minutes (the one they had gets boring). They want something, but you have no idea what. They want to be held, but by now there a 20 lbs human…
  • Childcare is expensive, but you probably already knew that.
  • Being a mom is a lot of work.

For this mothers day, I want to thank my wife for all of the hard work she does!

img_20190510_201610

Which Language Should I Use?

Lets start with a question: Does the programming language you use matter?

img_20190430_152215

I’ve been programming in Lisp and C++ for the last 2.5 years, before that I programmed in Java and C#, and before that I used Mathematica. I wouldn’t say I’m an expert in all of them, maybe competent but there area people who have been specialized in these languages for far longer then I, who understand them far deeper.


Writers note: Anything you write today, especially technical, will usually seem silly a few years down the line. It’s good to write it now and look back later to see how you’ve progressed.


One of my coworkers has the opinion that programming styles don’t come from programming languages themselves, but the users of said language. Take for example Perl. It is possible to write well documented, well tested Perl Code, it is possible to scale it up, and it’s possible to allow other authors to understand your code. If you don’t that though, it seems like you’ve offended the Perl Gods, it’s not how the programming community expects Perl to be.

Likewise, now-a-days with introductions of the Lambda, Java Repl, () => {} notation, and other niceties Java has become a programming language where you can write some decent code, still more verbose and boiler-platy then others, but not so bad. One of the issues is the community has opted for factory and object hierarchies as large as the companies that use it. Look no further then Class AbstractSingletonProxyFactoryBean.

I view C# as the “Good” java, it’s lambdas are nicer, it’s API’s seem cleaner and better thought out. It’s basically Microsoft looking at Java and doing a better version… But it’s still prone to the same idea’s as Java.

Are these issues with the programming languages though, or are they issues with the community around the programming languages.


Hint: It’s both…


Java is verbose, there’s no getting around it. It’s love of objects are annoying and factory patterns emerge. It’s not a bad language, it’s good at corporate large scale code bases. Half the issue is we use more of it then we need. We don’t need a factory factory, we’re looking to design for next decades problems when the code will in all likelihood be deleted next year.  C# lets you write functions outside of objects, so we can do a little better… C/C++ keep the kitchen sink for backwards compatibility, Rust can remove those shackles.

Lisp is my current favorite. You can fix your boilerplate code with MACROS, just be cautious and sparing. You can use objects if you wish, or you can stuck to structs. You have multiple inheritance with intelligent sub-classing, and you have generic functions that can be nicely hooked together. The main issue with Lisp code is people go overboard with macros, but culture will be culture.

So, does the programming language you use matter?

In some ways no, all languages are Turing complete…

A more intelligent answer is yes, when you use a language you inherit a way of thinking. If you learn a language, you learn the “Zen” of that language, you integrate into it’s culture. If your starting a company then you have a talent pool to pick from, if you are deep in a language then you may limit the job prospects.

In the same way, learning a different programming language is like learning a different language. The discount culture and way of thinking imbued in that language teaches you different ways of thinking and teaches different nuances. Ideally you should no several.

Lastly, since we humans like lists, here’s a list of programming languages I believe beneficial to knowledge of programming, if you know these (to some extant) you should be fairly well rounded:

Haskell, C/C++, Java, Lisp

I leave you with a picture:

img_20190501_131517

Going to the ELS

Last week I went to the European Lisp Symposium, the biggest conference for Lisp programmers in the world, suffice to say it’s not very big. If you haven’t been reading this blog for very long and want to know what Lisp is, feel free to look at Super-Primes where I programmed what I thought was a decent interview question in this language. As great as the conference was, this was my first conference away from the little one.

img_20190330_090907

My wife and I have taken Lyra to several conference, the Joint Mathematics Meeting and the South East Analysis Meeting, but they were both within the country and taking Lyra wasn’t very hard. For the ELS, taking Lyra would’ve meant Wenjing had to take days off, get a visa, Lyra would have to get a passport, and it would have messed up her sleep schedule. With so many impediments I went alone.

img_20190330_154632

As many parents will tell you, the first time your away from your baby is tough. You spent the first few months tied to them, they need continual attention, and it”’ feel like a full time job for two parents. With all of this work, you’re still happy (and tired), and when your gone there’s a baby sized hole.

img_20190324_131428

So, why did I go? There’s a few reasons.

My wife brought Lyra to the aquarium today, and she was SO excited, but I was at work. Talking to my co-worker Ron, I was quite sad, but he mentions how you won’t be there for all the exciting times, they have to grow, and you have work to do. It’s a sad thought, to miss out on the little one grabbing for sting rays, but she needs milk, and I’ll take her to plenty of other exciting things.

Secondly, this conference will help my career. It will allow me to meet other Lispers. I got to see academic papers on language design choices, how game developers are incorporating Lisp into their work, and how academics are using Lisp to catch people cheating at homework. I learned a lot, and I was able to network with people I would only get to meet at the conference. If you want a career, these are things you need to do.

Having a little one is amazing, but life doesn’t stop, yet you should try to spend as much time as possible with your family. ❤️

img_20190407_100055