-
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. -
25
SEP
2014Regex Code Equivalency
#!/usr/bin/env ruby -w Name = "Gray, James" !!(Name =~ /\AGray/) # => true Name.start_with?("Gray") # => true !!(Name =~ /James\z/) # => true Name.end_with?("James") # => true !!(Name =~ /Dana/) # => false Name.include?("Dana") # => false !!(Name =~ /\A\z/) # => false Name.empty? # => false !!(Name =~ /\AGray, James\z/) # => true Name == "Gray, James" # => true !!(Name =~ /\A(?:Gray, James|Gray, Dana)\z/) # => true ["Gray, James", "Gray, Dana"].include?(Name) # => true Name =~ /\A\w+/ && $& # => "Gray" Name[/\A\w+/] # => "Gray" Name =~ /\A(\w+),\s*(\w+)\z/ && $2 # => "James" Name[/\A(\w+),\s*(\w+)\z/, 2] # => "James" Name =~ /\A(?<last>\w+),\s*(?<first>\w+)\z/ && $~[:first] # => "James" Name[/\A(?<last>\w+),\s*(?<first>\w+)\z/, :first] # => "James" Name.scan(/^.*\n?/) # => ["Gray, James"] Name.lines # => ["Gray, James"] Name.scan(/./m) # => ["G", "r", "a", "y", ",", " ", "J", "a", "m", "e", "s"] Name.chars # => ["G", "r", "a", "y", ",", " ", "J", "a", "m", "e", "s"] Name.gsub(/[aeiou]/, "") # => "Gry, Jms" Name.delete("aeiou") # => "Gry, Jms" Name.gsub(/[aeiou]/, "X") # => "GrXy, JXmXs" Name.tr("aeiou", "X") # => "GrXy, JXmXs" # For the destructive operations that follow you can drop the `dup()` and # switch `sub()` to `sub!()`, as long as you don't care about the return value. Name.sub(/(?=,)/, " II") # => "Gray II, James" Name.dup.insert(Name.index(","), " II") # => "Gray II, James" Name.sub(/\A/, "Name: ") # => "Name: Gray, James" Name.dup.prepend("Name: ") # => "Name: Gray, James" Name.sub(/\A.*\z/m, "Gray, Dana") # => "Gray, Dana" Name.dup.replace("Gray, Dana") # => "Gray, Dana" Name.sub(/\A.*\z/m, "") # => "" Name.dup.clear # => "" Spacey = "\tsome space\r\n" Spacey.sub(/\A\s+/, "") # => "some space\r\n" Spacey.lstrip # => "some space\r\n" Spacey.sub(/\s+\z/, "") # => "\tsome space" Spacey.rstrip # => "\tsome space" Spacey.sub(/\A\s*(.+?)\s*\z/m, '\1') # => "some space" Spacey.strip # => "some space" Spacey.sub(/(?:\r?\n|\r)\z/m, "") # => "\tsome space" Spacey.chomp # => "\tsome space" Spacey.sub(/(?:\r\n|.)\z/m, "") # => "\tsome space" Spacey.chop # => "\tsome space" Spacey.gsub(/ +/, " ") # => "\tsome space\r\n" Spacey.squeeze(" ") # => "\tsome space\r\n"
-
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
-
28
MAY
2014Are We Teaching the Best Things?
I'm in Denver right now, mostly to see family. Being the geek that I am though, you know I snuck a little time for the local Rubyists. One of those Rubyists that I was lucky enough chat with is Katrina Owen.
I always love getting a chance to talk with Katrina. She's so thoughtful that she raises the level of discourse and makes me feel smarter. Plus, it turns out that Katrina and I have been thinking about similar things lately.
For my part, I've been thinking about the various students that I've taught to program over the years. I have taught many and because they all learned from me, they learned roughly the same way. What's interesting to me is how different the results have been from that technique. In some cases my students were all set after our lessons and they just began coding up a storm. Other students didn't seem to feel they were ready yet though. They had more of a "Now what do I do?" attitude at this stage.
Katrina raised a similar point from her time teaching in a developer school. When they would get to teaching language basics, they would show several constructs and how they are used. This is similar to how I teach. Just as I have observed, this works for some students. They can just take what they know and run from here. But they also found other students felt a little lost at this point.
-
11
APR
2012Riding the Testrocket
I say it a lot, but programming is about ideas. More specifically, it's about not running out of ideas.
Along these lines, I read the results of an interesting study recently. It was a study about how we think and solve problems. When I was in school, the belief was that we needed to cram our brain full of facts. We were pushed to memorize, memorize, memorize.
The more modern view of learning is that facts don't matter as much. Nowadays we just try to teach children how to think. The assumption is that they can find the facts they need, because information is so universally available, and their thinking skills will allow them to work their way to other bits of knowledge.
The study looked at people taught using both of these techniques and found some surprising results: us memorizers can often out think the thinkers. A leading theory about why that's the case is that the memorizers have more of a foundation to build their ideas off of. Thinkers may be starting closer to scratch each time. If so, they have further to go to get to the needed solution. Memorizers, on the other hand, may already have a lot of knowledge that puts them closer to the solution before they even need to start thinking.
-
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. -
1
JAN
2012Perl's Golf Culture
I'm stealing some time to write this while on vacation. I am also under the weather. Given that, we'll make this article short and easier on me to think up. That's not always a bad thing though. There are plenty of simple concepts I would like to get across. For example, let's talk about how Perl programmers do what it is they do.
Ruby's Sister Language
I spent plenty of time in the Perl camps and I really learned a lot about programming there. That may shock you to hear, because Perl programmers often get a bad wrap from the rest of the programming community.
One reason they catch a lot flak is that their language is often terse to the point of obscurity. We joke that Perl is a "write only" language or too hard for other developers to read. That would be bad enough on its own, but Perl programmers seem to intentionally make this worse.
Perl programmers love to play the programmer's version of golf. That is writing a program with the fewest possible keystrokes. To shrink their program's size, they will resort to every dirty trick in the book, including:
-
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. -
2
JUL
2009Getting Ready for Ruby 1.9
We've all been waiting for Ruby 1.9 to reach maturity for some time now. We've complained about things like Ruby's speed and weak character encoding support. We knew 1.9 could improve things, but it brings pretty big changes and a lot of Ruby 1.8 code needs updating before it can really be used there. For these and other reasons, the official production release came and went while most of us have stuck with 1.8 for our day to day needs.
I think we're reaching the tipping point though. Rails runs on 1.9 now and many other libraries are beginning to become compatible. We may not yet have the full range of 1.8 goodies available on the new platform, but many of the staples are moving over and it's looking like we can now do some serious work there.
Which means it's finally time for us to learn this 1.9 stuff.
There are several good sources of Ruby 1.9 information now, so you have choices. I'm going to tell you about three I like. Be warned, this is a super biased list, but I really hope it will be helpful to others.
-
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