Robbie Clutton's blog
I tried to explain Options in Scala in a lightening talk this week and I don’t think I did a particular good job at this. I started by talking about how you might use Options instead of doing null checks in a first step towards a more idiomatic way of using Scala, but perhaps I should have skipped that and gone straight to the interesting parts. So while my presentation is available with those comments, here I will skip the first half of that and get to it.
An Option represents an optional value, it either contains a value, or it does not. In Scala the terms used are that an option has Some of X, or None. While this does give you some nice wrap around doing Null checks, it doesn’t buy you much more than that until you consider that an Option can be thought about as a sequence of zero or one elements, and that you can use functions on an Option that you would do on a list. This gives you access to map, filter, flat map and all the others.
This in turn opens up the world of transformations and list comprehensions. Now we’re going into idiomatic Scala. One of the most used elements in Scala that I’ve seen is taking one object and transforming that into another. When transformations are done a few at a time, you can quickly eliminate a lot of plumbing code through chaining calls to get to what you need. You can do this safely using Options as each step in the chain returns an Option, and the first step in the chain to return a None will evaluate the whole expression as None.
This example has an option of a person, transforms that into an option of department and then into an option of the department name as a string. If at any time the object is None, the whole statement will return None. If it gets through to the department name, it will return a Some of String (Some[String]). The underscore in the example is the value within the Option after the map has been applied. This can be assigned to a locally scoped variable too, but for conciseness, I’m using the underscore.
val personOption = Some(person)
val departmentName1 = personOption.flatMap { person => person.department } map { department => department.name }
val departmentName2 = personOption flatMap { _ department } map { _ name }
Options have functions that allow you to retrieve the value, retrieve the value with a given default if the value is None, or check to see if the object is defined. To get the name of the department, we can do:
val deptName = departmentName1 getOrElse (“No department”)
That’s cool, but we can go one further with list comprehension. This is where we turn a list into another list. Remember earlier we said an Option can be considered an sequence of zero or more elements, so we can apply list comprehension to an option and return an option. Each line here will assign from right to left, and if at any step something on the right is None, the expression will be None. We can also apply conditions into the comprehension, so that if the name of the department is engineering the whole expression returns None.
val departmentName3 = for {
person <- personOption
department <- person.department
} yield department.name
Both of these method can be applied to lists as well as options, so that if personOption was actually a list of people, the result would be a list of department names. Here we apply the same code to a list to get all the non-engineering department names.
val person2 = Person(Some(Department("Design")))
val people = List(person, person2)
val nonEngineeringDepartments = for {
person <- people
department <- person.department if department.name != "Engineering"
} yield department.name
This train of thought started when I wanted to do something in Ruby that I knew how to do in Scala and it turned into me trying to explain some of these concepts in Scala. I’m still fairly new to Ruby, and I’m not saying ‘I wish I could do this in Ruby’, more ‘I wish I knew if I could do this in Ruby’.
More code is available in this Gist: https://gist.github.com/059d04ccc03d86081f84
There's always been an mix of excitement and fear when starting a new job for me. There are many questions that you cannot know the answer to until you've experienced it: Will I enjoy the work? Will I get along with my new colleagues? Will I pick up the new tools, languages and processes quickly enough not to be an annoyance? Will the company be everything I think it is?
I tend to have these questions floating in my mind for every new position I've started. I've never had to throw in a heady new mix of relocating to a new city, a new country, at the same time. I've travelled abroad for work before, but I've never relocated. The few days before and after starting at Pivotal were filled with that particular doubt that comes with things that are very difficult or impossible to undo: Had I made the right decision?
A close friend of mine said it sounded character building. That's probably very true and certainly the most polite way I can think of putting it.
As it turns out, I needn't be worried. My new team-mates were jovial and bright. They made me feel at home and were very patient with me while I fumbled my way through unfamiliar tools and frameworks. Although I did feel like a bit of a dead weight on certain things, I felt immediately at home with the pro-agile processes and good engineering practices that I had worked within for most of my career.
The first few weeks were intense and fast moving. It felt like going on holiday with a basic grasp of the local language only for everyone to speak at a hundred miles an hour while you try and keep up, trying to keep your head above water. Most nights I would go home drained, feeling like I'd completed a mental marathon. I found my feet a little more each day, and felt like I was chipping away at the burden/contribution ratio.
A month in now and I feel I still have a lot to learn, but that's an environment I enjoy being in. I regard software engineering as professional problem solving and if I'm not learning I feel like I'm standing still. Standing still makes me feel like I'm solving the same problem over again. Looking for opportunities where I can learn more has always been a big motivating factor for me when choosing a new job, and there are great opportunities here.
That early doubt about moving to the US, to New York and joining Pivotal has been soundly banished. Had I made the right decision? Definitely.
I was pairing with Adam today when we had a chance to write a little Javascript. This was an interaction that changed state in the DOM without changing the page location, and we initially used an anchor element. I remembered a spectacular rant by Dan Webb about why anchors shouldn't be used in this way. I couldn't quite find the tweets I was looking for, so I asked.
[View the conversation between Dan Webb and myself here on Storify]
Essentially the gist is "if you don't have a URI, then don't use the anchor tag". That means not using markup like
<a href="#">click</a>
I can hear Matt Andrews telling me to put a javascript void call in the href, and although I understand the point that it won't do anything if Javascript isn't enabled on the page whereas using '#' would, and that it states its intentions through calling Javascript directly, I now think we can do a little better. So we shouldn't do this either:
<a href="javascript:void(0)">click</a>
I did the first pass of a refactor and started to use a span element before Berger pointed out that that was probably just as non-semantic as the anchor element. I had to concede the point.
For our case, the best option was an input element with type button. That summed up the best interaction for our use case; manipulating the DOM on a user action, without referencing another resource or an anchored point within the current document.
The thing is, it's a small change and there are so many examples on the web where the href=# pattern is used. It does work, so why bother changing it? Well yes, while it might work, this isn't the purpose of an anchor tag. There are other elements that will work just as well for you and make semantic sense. If we do that, then we can all make Dan a little happier.
