-
31
OCT
2014How to Avoid Taking a Dart to the Knee
I've been playing with Dart quite a bit lately. I really enjoy the language, but there are always snags that trip up those coming from other backgrounds. Here are the top three issues that have bit me in Dart, in the hopes of saving others some pain:
The Truth and Nothing But the Truth… Literally!
One of the challenges of any language is figuring out what it considers to be truthy in conditional expressions. Each system has its twists, but I find Dart to be extra strict in this case.
Here's some code illustrating the rule:
bool isTruthy(Object condition) { return !!condition; } void main() { var tests = [true, false, null, 42, 0, "", [ ], new Object()]; for (var test in tests) { print("$test is ${isTruthy(test)}"); } }
That outputs:
$ dart truthiness.dart true is true false is false null is false 42 is false 0 is false is false [] is false Instance of 'Object' is false
As you can see the literal
true
(just that one object) is truthy in Dart and everything else is consideredfalse
. I'm in the habit of playing pretty fast and loose with truthiness from all of my time working with Ruby, so this has surprised me a few times. -
24
OCT
2014The Three Tick Sort
Yesterday I showed a newer programmer some code like
scores.sort_by(&:reverse)
. This provoked a comment about how they where going to look upsort_by()
later to figure out what magic is involved here. It made me sad to realize how many cool tricks they weren't going to see in that bit of documentation.Allow me to enumerate those tricks for you, but first let's flesh out an example. Consider this code:
scores = { fifteen: 2, five_card_run: 5, five_card_flush: 5, four_card_run: 4, four_card_flush: 4, his_nobs: 1, pair: 2, three_card_run: 3, } scores.sort_by(&:reverse).each do |name, score| puts "Score #{score} for #{name}." end # >> Score 1 for his_nobs. # >> Score 2 for fifteen. # >> Score 2 for pair. # >> Score 3 for three_card_run. # >> Score 4 for four_card_flush. # >> Score 4 for four_card_run. # >> Score 5 for five_card_flush. # >> Score 5 for five_card_run.
In this case, the magic method call (
scores.sort_by(&:reverse)
) has reordered a list of Cribbage hands first by point value and then alphabetically ("ASCIIabetically" in truth). How this happens is a pretty interesting journey though. -
11
SEP
2014Experimenting With Ownership
Let's use a trivial exercise to see what we can learn about ownership, moving, borrowing, and more in Rust. Here's the idea:
- We'll allocate a list of numbers
- We'll add one to each number in the list
- We'll print the resulting list of numbers
This is a simple process requiring only a few lines of code:
fn main() { let mut numbers = vec![1u, 2, 3]; for n in numbers.mut_iter() { *n += 1; } println!("{}", numbers); }
The output is hopefully what we all expect to see:
$ ./one_function [2, 3, 4]
In this code there is just one variable:
numbers
. That variable owns a list of numbers on the heap and it's scope is limited to themain()
function, which is just a way to say that the data exists for the length of that function call. Since all three steps happen in that one function call, ownership doesn't really affect us here.To better examine what ownership really means, let's add one small twist to our exercise:
- The increment of each number in the list must happen in a separate function
-
11
FEB
2012Test Driving an Algorithm (Part 2)
In the last article, I built a quick and dirty solution to PuzzleNode's Hitting Rock Bottom puzzle. I didn't use specs, objects, or even multiple files. In this article, I'll repeat the exercise but using all of those elements. Let's see how that affects the results.
The Disciplined Approach
This time, I'll reign in my desire to push forward and solve the problem more carefully, without having to build a fully formed algorithm all at once.
I still think the input is the right place to start. I need to read in the units. Let's add a spec for that in
spec/parser_spec.rb
:require "minitest/autorun" require "stringio" require "hitting_rock_bottom/parser" describe HittingRockBottom::Parser do let(:units) { 42 } let(:io) { StringIO.new(units.to_s) } let(:parser) { HittingRockBottom::Parser.new(io) } it "reads the units number from the beginning of the stream" do parser.units.must_equal(units) end end
If you haven't seen the standard
stringio
library before, it simply wraps aString
with anIO
interface. That's will allow me to callgets()
and otherIO
methods on it in my implementation. It's perfect for tests like this. -
21
JAN
2012Iteration Patterns
I love studying how the human brain works. It's an amazing biological machine capable of impressive feats. Of course, it also has its quirks.
For example, the brain is a terrific pattern matcher. That's probably one of its favorite activities. It wants to do this so much that it will often even find patterns that aren't there.
While this "feature" of your brain can get you into trouble, you can also make it work for you. Some parts of programming really are about patterns. If you prime your brain with the right data, it will just take over and do one of the things it does best.
How I Teach Iterators
One evening, at a post Ruby conference dinner, Glenn Vanderburg and I had a lengthy discussion about iterators and patterns. During this discussion we nailed down a plan for how the iterators could be taught.
I know that we've both used the strategy we came up with in multiple Ruby trainings and we have both seen it work wonders. This is hands down the best way to learn the iterators, in my opinion.
-
21
DEC
2011Refactoring: rcat
I use these Rubies in the Rough articles to teach how I think about code. Well, I have a scary admission to make: I didn't really understand refactoring until I was many years into being a programmer. Sure, I knew what it meant, but I just didn't get it. I hope to save you from the same mistake.
Refactoring is important. Very important. It may be one of the most important things we do as programmers. If I learned one thing from reading Smalltalk Best Practice Patterns, it's that code's primary purpose is to communicate with the reader. Let's face it though, when we are trying to get something working, it's often like stumbling around in the dark. We are running into all kinds of things, breaking stuff, and just trying to reach that "Holy cow it works!" moment. We're probably not thinking too long and hard about how well this mess we are making communicates and that's perfectly fine.
Refactoring is where you get to fix that. It's about taking working code and making it sexy. Note that I said it starts with working code. Until you have that, there's nothing worth communicating to a potential reader. Make it work, then make it sexy. (I believe that saying really involves speed, but that's a very different conversation we can have at a later date.)
-
11
DEC
2011Even More Eloquent Ruby
I recently read Eloquent Ruby so we can discuss it on an upcoming Ruby Rogues episode with author Russ Olsen. In short, the book is fantastic. You should definitely read it.
I, on the other hand, am cranky. When you have read Ruby books since the first one was published (literally!), you can always find something to complain about. There are a handful of examples in Eloquent Ruby that could be better, in my opinion. I thought I would show you some of those. If you've read the book, this should make a nice supplement. Don't worry if you haven't though, you will still be able to follow these ideas just fine. I also won't spoil the ending, but you all know that the Rubyist saves the day.
Before I start, let me stress one more time that this is a terrific book. It has so many clear discussions of real issues Rubyists must face when writing code like class variables, the differences between
lambda()
,proc()
, andProc.new()
, how to use blocks and modules, why people think Ruby leaks memory and how you can avoid those problems, plus more. Don't let any fun I poke at the examples below change your view of this book. If I didn't love it, I wouldn't have bothered to write this article. -
7
JAN
2009The Evils of the For Loop
I've never liked the
for…in
loop in Ruby. I cringe every time I see it in examples (Rails seems to put it in views a lot) and I tend to switch it to aneach()
call. It really bugs me.That's mostly just my gut reaction, but if I had to put it into words it's that I fell in love with Ruby's iterators early on and
for
just doesn't seem to fit in well with them. I don't think that's just my emotions talking either, it really doesn't fit in. I'll try to show you why I say that.First, let's see what I'm talking about. We are all pretty comfortable with
each()
, right?(1..3).each { |i| p i } # >> 1 # >> 2 # >> 3
I doubt that surprises anyone. Many of you probably also know that Ruby allows you to write that as:
for i in 1..3 p i end # >> 1 # >> 2 # >> 3
That's almost the same thing. It really does use
each()
under the hood, for example:class MyEachThing def each yield 1 yield 42 yield 2 yield 42 yield 3 end end for i in MyEachThing.new p i end # >> 1 # >> 42 # >> 2 # >> 42 # >> 3
-
2
JAN
2008Getting FasterCSV Ready for Ruby 1.9
The call came down from on high just before the Ruby 1.9 release: replace the standard
csv.rb
library withfaster_csv.rb
. With only hours to make the change it was a little harder than I expected. TheFasterCSV
code base was pretty vanilla Ruby, but it required more work than I would have guessed to get running on Ruby 1.9. Let me share a few of the tips I learned while doctoring the code in the hope that it will help others get their code ready for Ruby 1.9.Ruby's
String
Class Grows UpOne of the biggest changes in Ruby 1.9 is the addition of m17n (multilingualization). This means that Ruby's Strings are now encoding aware and we must clarify in our code if we are working with bytes, characters, or lines.
This is a good change, but the odds are that most of us have lazily used the old way to our advantage in the past. If you've ever written code like:
lines = str.to_a
you have bad habits to break. I sure did. Under Ruby 1.9 that code would translate to:
lines = str.lines.to_a
-
21
MAR
2006The Why and How of Iterators
A friend of mine has been asking some general questions about iterators in private emails we have traded. I wanted to put some of my answers here, in case they appeal to a wider audience.
Why do we have iterators?
First, let's invent a little data to play with:
>> Name = Struct.new(:first, :last) => Name >> names = [ Name.new("James", "Gray"), ?> Name.new("Dana", "Gray"), ?> Name.new("Caleb", "Nordloh"), ?> Name.new("Tina", "Nordloh") ] => [#<struct Name first="James", last="Gray">, #<struct Name first="Dana", last="Gray">, #<struct Name first="Caleb", last="Nordloh">, #<struct Name first="Tina", last="Nordloh">]
Now let's assume we want to print some names. We can use the
each()
iterator for that, no index:>> names.each { |name| puts "#{name.last}, #{name.first}" } Gray, James Gray, Dana Nordloh, Caleb Nordloh, Tina => [#<struct Name first="James", last="Gray">, #<struct Name first="Dana", last="Gray">, #<struct Name first="Caleb", last="Nordloh">, #<struct Name first="Tina", last="Nordloh">]