NSF Stuff:
- Kevin showed me a really interesting video where a C# API developer wanted to make his interface very understandable, and to do this was trying to avoid returning null in a method to try to read a string from a file. He felt that this would be inconsistent with the rest of his interface, as other methods that returned strings were guaranteed to not be null.
- He went through various different approaches, which should hold true (to some extent) in any language.
- What he settled on was returning a Maybe, a collection guaranteed to have either 0 or 1 elements: 0 elements if the file couldn't be read, and 1 if it could, where the element was the string. This way, he could write code to handle a case with 0 elements much more fluidly than just having a null check.
- I also learned some stuff about C#!
- I guess the string data type is a primitive, because it was written as "string" when declaring the return type for his methods. If my memory is correct, I think you can write it as String as well.
- I also learned about the out parameter in C#, which was used in one of the approaches to the problem, albeit one that the guy in the video didn't like. It's still useful to know that you could have a specific variable be modified by a separate method, though. I think that's pretty cool.
Ruby:
- Updated code and committed to repo.
- Fixed ThreadPool#join_all so that it works correctly.
- Now, when called, it sets the finished flag to true, then does one of two things:
- If there are still elements in the task queue, Thread#join is called on each of the worker threads. Since the finish flag is now true, each worker thread continues to work as normal, but will abort once it completes a task and finds the task queue to be empty. Once all worker threads have completed tasks and found the queue to be empty, the #join_all method will release the lock on the thread it is called in (the main thread, most likely) and the program can continue on.
- If the task queue is empty when #join_all is called, ThreadPool#kill_all is called, which terminates all worker threads. This prevents a deadlock where all the threads are waiting on the queue already, and therefore never check to see that the finished flag has been set to true.
- I also cleaned up some things in the code, and learned some stuff along the way!
- I had a while loop that was something like
int i = 0 while i < 20 do ... i+=1 end
However this is very un-ruby like. I changed this to be
20.times do |i| ... end
which is much cleaner and easier to read. In doing this, I also realized that I had code that read:some_integer.times.each_with_index do |i|
which is just awful. It can be rewritten with the exact same functionality assome_integer.times do |i|
. I'm not sure why I thought I needed to call #each on that, let alone #each_with_index! (If #each is redundant, #each_with_index is doubly redundant because you are already using the integer as an index, so getting the index of that index makes no sense)
Ruby, Java, and now C#, you're becoming a multi-lingual programmer ;-)
ReplyDelete