3/20/2014 Affordances
http://localhost:9090/onepage 1/67
Affordances inProgramming Languages
Randy CoulmanPrincipal Software Engineer
http://randycoulman.com
@randycoulman
randycoulman
3/20/2014 Affordances
http://localhost:9090/onepage 2/67
Satu Kyröläinen http://www.satukyrolainen.com/affordances/
3/20/2014 Affordances
http://localhost:9090/onepage 3/67
Satu Kyröläinen http://www.satukyrolainen.com/affordances/
3/20/2014 Affordances
http://localhost:9090/onepage 4/67
Affordance
A quality of an object or environment that allows someone toperform an action.
3/20/2014 Affordances
http://localhost:9090/onepage 5/67
Nicolas Nova http://www.flickr.com/photos/nnova/2252222949/
3/20/2014 Affordances
http://localhost:9090/onepage 6/67
William Lindeke http://tcsidewalks.blogspot.com/2009/06/signsoftimes14.html
3/20/2014 Affordances
http://localhost:9090/onepage 7/67
Yoni Alter http://www.yoniishappy.com/Tubeescalators
3/20/2014 Affordances
http://localhost:9090/onepage 8/67
Affordances and Software
3/20/2014 Affordances
http://localhost:9090/onepage 9/67
Amir Rajan (@amirrajan)
Coding Out Loud REST APIs series
http://vimeo.com/channels/659338
3/20/2014 Affordances
http://localhost:9090/onepage 10/67
ExamplePoints
Smalltalk > Ruby
3/20/2014 Affordances
http://localhost:9090/onepage 11/67
class Point def initialize(x, y) @x = x @y = y endend
Point.new(3, 4)
3/20/2014 Affordances
http://localhost:9090/onepage 12/67
http://images.cryhavok.org/d/255622/Polar+and+Cartesian+Bears.jpg
3/20/2014 Affordances
http://localhost:9090/onepage 13/67
θ
r sinθ
r cosθ
r
x
y
http://upload.wikimedia.org/wikipedia/commons/7/78/Polar_to_cartesian.svg
3/20/2014 Affordances
http://localhost:9090/onepage 14/67
class Point def initialize(x, y) @x = x @y = y endend
Point.new(3, 4)
3/20/2014 Affordances
http://localhost:9090/onepage 15/67
Point class>>x: anX y: aY ̂self new initializeX: anX y: aY
Point>>initializeX: anX y: aY x := anX. y := aY
Point x: 3 y: 4
3/20/2014 Affordances
http://localhost:9090/onepage 16/67
Point class>> r: radius theta: angleInRadians ̂self x: radius * angleInRadians cos y: radius * angleInRadians sin
Point r: 5 theta: 0.927295
3/20/2014 Affordances
http://localhost:9090/onepage 17/67
Affordance
Named Constructors
3/20/2014 Affordances
http://localhost:9090/onepage 18/67
class Point def self.xy(x, y) new(x, y) end
def self.polar(r, theta) xy(r * Math.cos(theta), r * Math.sin(theta)) end
private_class_method :new
# ... rest same as beforeend
Point.xy(3, 4)Point.polar(5, 0.927295)
3/20/2014 Affordances
http://localhost:9090/onepage 19/67
ExampleFind/DetectSmalltalk > Ruby
3/20/2014 Affordances
http://localhost:9090/onepage 20/67
#(2 4 6 8) detect: [:each | each odd]
"Unhandled exception: Element Not Found"
3/20/2014 Affordances
http://localhost:9090/onepage 21/67
[2, 4, 6, 8].find { |n| n.odd? }
# => nil
3/20/2014 Affordances
http://localhost:9090/onepage 22/67
#(2 4 6 8) detect: [:each | each odd] ifNone: [#none]
"#none"
3/20/2014 Affordances
http://localhost:9090/onepage 23/67
Affordance
Multiple Blocks
3/20/2014 Affordances
http://localhost:9090/onepage 24/67
[2, 4, 6, 8].find(-> {:none}) { |n| n.odd?} # => :none
3/20/2014 Affordances
http://localhost:9090/onepage 25/67
Linguistic Relativitya.k.a. The SapirWhorf Hypothesis
"[T]he structure of a language affects the ways in which itsrespective speakers conceptualize their world ... or otherwiseinfluences their cognitive processes."
http://en.wikipedia.org/wiki/Linguistic_relativity
3/20/2014 Affordances
http://localhost:9090/onepage 26/67
When Code CriesCory Foy at SCNA 2012
http://vimeo.com/53986875
What does a language allow you to say?
What does a language force you to say?
3/20/2014 Affordances
http://localhost:9090/onepage 27/67
The Power and Philsophy of RubyMatz at OSCON 2003
http://www.rubyist.net/~matz/slides/oscon2003/mgp00001.html
"Languages are not only tools to communicate, but also toolsto think."
3/20/2014 Affordances
http://localhost:9090/onepage 28/67
ExampleCleaning Up After Yourself
C++ > Ruby
3/20/2014 Affordances
http://localhost:9090/onepage 29/67
if ((err = SSLFreeBuffer(&hashCtx)) != 0) goto fail;if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0) goto fail;if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != goto fail;if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != goto fail;if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != goto fail; goto fail;if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail;
//...
fail: SSLFreeBuffer(&signedHashes); SSLFreeBuffer(&hashCtx); return err;
3/20/2014 Affordances
http://localhost:9090/onepage 30/67
#include "support.h"#include <iostream>
void foo(){ Resource* resource = acquireResource(); bar(resource);
if (baz(resource) != 42) return;
std::cout << "Completed successfully!" << std::endl;
releaseResource(resource);}
3/20/2014 Affordances
http://localhost:9090/onepage 31/67
$ ./brokenAcquiring resourceCaught exception: oops!
3/20/2014 Affordances
http://localhost:9090/onepage 32/67
#include "support.h"#include <iostream>
void foo(){ Resource* resource = acquireResource();
try { bar(resource);
if (baz(resource) == 42) { std::cout << "Completed successfully!" << std::endl; } } catch(std::exception& e) { releaseResource(resource); throw; }
releaseResource(resource);}
3/20/2014 Affordances
http://localhost:9090/onepage 33/67
$ ./wordyAcquiring resourceReleasing resourceCaught exception: oops!
3/20/2014 Affordances
http://localhost:9090/onepage 34/67
#include "support.h"#include <iostream>
void foo(){ Resource* resource = acquireResource();
try { bar(resource);
if (baz(resource) == 42) { std::cout << "Completed successfully!" << std::endl; } } catch(std::exception& e) { releaseResource(resource); throw; }
releaseResource(resource);}
3/20/2014 Affordances
http://localhost:9090/onepage 35/67
3/20/2014 Affordances
http://localhost:9090/onepage 36/67
RAIIResource Acquisition Is Initialization
Acquire resources in the constructor
Release them in the destructor
3/20/2014 Affordances
http://localhost:9090/onepage 37/67
#include "SafeResource.h"#include "support.h"
SafeResource::SafeResource() : resource(acquireResource()){}
SafeResource::~SafeResource(){ releaseResource(resource);}
Resource* SafeResource::get(){ return resource;}
3/20/2014 Affordances
http://localhost:9090/onepage 38/67
#include "SafeResource.h"#include "support.h"#include <iostream>
void foo(){ SafeResource resource; bar(resource.get());
if (baz(resource.get()) != 42) return
std::cout << "Completed successfully!" << std::endl;}
3/20/2014 Affordances
http://localhost:9090/onepage 39/67
$ ./raiiAcquiring resourceReleasing resourceCaught exception: oops!
3/20/2014 Affordances
http://localhost:9090/onepage 40/67
Affordance
Deterministic Destructors
3/20/2014 Affordances
http://localhost:9090/onepage 41/67
Ruby doesn't have deterministic destructors.So what can we do instead?
3/20/2014 Affordances
http://localhost:9090/onepage 42/67
Blocks!
3/20/2014 Affordances
http://localhost:9090/onepage 43/67
class SafeResource def self.acquire resource = self.new yield resource ensure resource.release end
def initialize puts "Acquiring resource" @resource = Object.new end
def release puts "Releasing resource" @resource = nil end
3/20/2014 Affordances
http://localhost:9090/onepage 44/67
require_relative "support"require_relative "safe_resource"
def foo SafeResource.acquire do |resource| bar(resource)
return unless baz(resource) == 42
puts "Completed successfully!" endend
3/20/2014 Affordances
http://localhost:9090/onepage 45/67
$ ruby driver.rbAcquiring resourceReleasing resourceCaught exception: oops!
3/20/2014 Affordances
http://localhost:9090/onepage 46/67
ExampleImageReaderSmalltalk > Ruby
3/20/2014 Affordances
http://localhost:9090/onepage 47/67
ImageReader class>>fromFile: aFilename | readerClass imageStream reader |
imageStream := aFilename readStream binary. [readerClass := self readerClassFor: imageStream. readerClass ifNil: [̂self error: 'Unknown image type: ', aFilename asString]. reader := readerClass on: imageStream] ensure: [imageStream close]. ̂reader
3/20/2014 Affordances
http://localhost:9090/onepage 48/67
ImageReader class>>readerClassFor: imageStream ̂self subclasses detect: [:eachClass | imageStream reset. [eachClass canRead: imageStream] ensure: [imageStream reset]] ifNone: [nil]
3/20/2014 Affordances
http://localhost:9090/onepage 49/67
Affordance
Subclass Iteration
3/20/2014 Affordances
http://localhost:9090/onepage 50/67
class ImageReader
def self.read(filename) File.open(filename, "rb") do |io| reader_class = find_reader_class(io) raise "Unknown image type: #{filename}" unless reader_class reader_class.new(io) end end
#...end
3/20/2014 Affordances
http://localhost:9090/onepage 51/67
class ImageReader #...
def self.find_reader_class(io) subclasses.find { |reader| begin io.rewind reader.can_read?(io) ensure io.rewind end } end
#...end
3/20/2014 Affordances
http://localhost:9090/onepage 52/67
class ImageReader #...
def self.inherited(subclass) subclasses << subclass end
def self.subclasses @subclasses ||= [] end
#...end
3/20/2014 Affordances
http://localhost:9090/onepage 53/67
class BMPImageReader < ImageReader def self.can_read?(io) io.read(2) == "BM" end
def read_image puts "Reading BMP" endend
3/20/2014 Affordances
http://localhost:9090/onepage 54/67
class JPGImageReader < ImageReader def self.can_read?(io) io.read(2) == "\xFF\xD8".b end
def read_image puts "Reading JPG" endend
3/20/2014 Affordances
http://localhost:9090/onepage 55/67
class PNGImageReader < ImageReader def self.can_read?(io) io.read(8) == "\x89PNG\r\n\x1A\n".b end
def read_image puts "Reading PNG" endend
3/20/2014 Affordances
http://localhost:9090/onepage 56/67
require_relative "image_readers"
%w{bmp jpg png}.each do |ext| ImageReader.read("example.#{ext}")end
3/20/2014 Affordances
http://localhost:9090/onepage 57/67
$ ruby subclasses.rbReading BMPReading JPGReading PNG
3/20/2014 Affordances
http://localhost:9090/onepage 58/67
Takeaways
3/20/2014 Affordances
http://localhost:9090/onepage 59/67
Languages afford certain designsand inhibit others
3/20/2014 Affordances
http://localhost:9090/onepage 60/67
Languages influence thought
3/20/2014 Affordances
http://localhost:9090/onepage 61/67
Learning new languages willincrease your "solution space"
3/20/2014 Affordances
http://localhost:9090/onepage 62/67
Don't go too far
3/20/2014 Affordances
http://localhost:9090/onepage 63/67
Want More?http://randycoulman.com/blog/categories/affordances/
3/20/2014 Affordances
http://localhost:9090/onepage 64/67
AcknowledgementsKey Technology (http://www.key.net/)
Rogue.rb (@roguerb)
Jen Myers (@antiheroine)
3/20/2014 Affordances
http://localhost:9090/onepage 65/67
ReferencesThe Design of Every Day Things Donald Norman
Coding Out Loud Amir Rajan
Linguistic Relativity Wikipedia article
When Code Cries Cory Foy at SCNA 2012
The Power and Philosophy of Ruby Matz at OSCON 2003
3/20/2014 Affordances
http://localhost:9090/onepage 66/67
Questions?
3/20/2014 Affordances
http://localhost:9090/onepage 67/67
Randy Coulmanhttp://speakerrate.com/randycoulman
http://www.slideshare.net/randycoulmanhttp://randycoulman.com
@randycoulman
randycoulman
Top Related