I understand that x |= y basically means x = x|y. The operator | is defined for the class Set as calculating the union of two sets. Indeed we can see:
require 'set'
r = Set.new(%w(a b));
s = Set.new(%w(c d));
r |= s; # r => #<Set: {"a", "b", "c", "d"}>
But see for instance the following class definition:
class Demo;
def initialize(s);
#x = s.dup;
end;
attr_accessor :x;
def m!(t);
x |= t.x; ' <--- HERE TROUBLE!
end;
end
I'm using this class like this:
u = Demo.new(Set.new(%w(a b)))
v = Demo.new(Set.new(%w(c d)))
u.m!(v)
If I now look at u.x, I see that it still holds the set a,b and not a,b,c,d. My feeling is that this comes from the fact I'm using the attribut accessor, in particular the setter method. If I would write #x |= t.x, it would work. Could it be that the left hand side of x |= t.x uses the getter x and not the setter x=, thereby creating the union in a temporary Set object?
BTW, I'm using a fairly old version of Ruby (JRuby 1.7.x, corresponding roughly to the language version of Ruby 1.9.3).
The reason for this is that in
x = 3
x is always interpreted as a local variable before ruby starts looking for a method x=. This means, that your method translates to:
def m!(t)
x = nil # local variable initialization
x = x | t.x
end;
To solve this, you need to use explicit self to force method call:
def m!(t);
self.x |= t.x
end
Another note - please do not use semicolons in ruby. There are only a very rare situations they needed but we generally avoid them
I want to do a compact error checking assignment in ruby.
class User
attr_accessor :x
end
user = User.new
user.x = 5
a = b || user.x
I want to figure out which of these is the first valid attribute and assign it, similarly to how javascript handles different API's, i.e.:
var AudioContext = window.AudioContext||window.webkitAudioContext;
audioContext = new AudioContext();
and figure out which was valid.
With ruby however, similar syntax gives errors when I reference an undefined variable. i.e.:
a = 10
b = 7
c = a || b
c # => 10
vs
a = 10
c = b || a # => Error: b is undefined
Is there a clean way to do this? Or at the very least, what is the best way to do this?
I'm working with a large code that I haven't created, and I am not permitted to change it.
UPDATE:
I think the real use case is kind of relevant to this question so i'll explain it.
I have a module which saves something to the DB every time a model in rails is updated, this update requires an id field, this id field is inside the model that includes my module, however not every model maintains the same naming convention for this id. The ternary operator equivalent of what I want to do is
id = defined?(self.id) ? self.id : defined?(self.game_id) ? self.game_id : defined?(self.app_id) ? self.app_id : nil
which is hard to read and write compared to the js equivalent
You can use defined? to test if a name refers to something recognizable in current scope (method, local variable, etc):
c = defined?(b) ? b : a # of course this assumes that 'a' is defined
Although it's pretty iffy that you're assigning from local variables that haven't been defined - how does that come up?
Or are you always testing for properties? In which case, respond_do? may be the better choice.
Edit
I was using the ternary operator as an example, you could always use an if/elsif/else block, of course.
Since you're only testing methods, respond_to? is more convenient than defined? because it takes symbols, rather than expressions, to which you can apply any logic you want:
def invoke_first *names
names.each do |name|
if respond_to? name
return send name
end
end
return nil # or, more likely, raise something
end
or, more concisely:
def invoke_first *names
send names.find(lambda {raise 'no method'}){|n| respond_to?(n)}
end
include in your model and use as:
invoke_first(:foo_id, :bar_id, :baz_id)
Okay so there is a much more concise way of doing this, but it has a side-effect of assigning something to the undefined var.
This breaks
a = 1
c = b || a # => b is undefined
This works
a = 1
c = b ||= a # => c == 1, b == 1
The above assigns b to c if b is valid, then falls back on a. a is only assigned to b (and c) if b is undefined/invalid.
How do I do this in Moonscript?
function a:do_something(b)
print(b)
end
Nothing I tried would compile and I didn't see anything in their documentation.
In Lua what you wrote is syntactic sugar for the following:
a.do_something = function(self, b)
print(b)
end
So you would do just that in MoonScript. (note the => as a shorthand for adding self to the front of the function's argument list)
a.do_something = (b) =>
print b
In MoonScript you'd do:
a.dosomething = (self, b) ->
print b
The -> and => symbols are aliases of the function keyword.
a.dosomething = (b) =>
print b
Using the => (Fat arrow) style as above, adds the scope, ie. self, to the arguments list automatically.
what you're looking for is class.__base:
class C
a: (x)=> print x
C.__base.b = (y)=> #a y*2
i=C!
i\b 5
--prints 10
Not infrequently, one wants to implement the <=> (comparison, or "spaceship") operator on a product data type, i.e., a class with multiple fields (all of which (we hope!) already have <=> implemented), comparing the fields in a certain order.
def <=>(o)
f1 < o.f1 && (return -1)
f1 > o.f1 && (return 1)
f2 < o.f2 && (return -1)
f2 > o.f2 && (return 1)
return 0
end
This is both tedious and error-prone, especially with a lot of fields. It's error-prone enough that I frequently feel I should unit test that function, which just adds to the tediousness and verbosity.
Haskell offers a particularly nice way of doing this:
import Data.Monoid (mappend)
import Data.Ord (comparing)
-- From the standard library:
-- data Ordering = LT | EQ | GT
data D = D { f3 :: Int, f2 :: Double, f1 :: Char } deriving Show
compareD :: D -> D -> Ordering
compareD = foldl1 mappend [comparing f1, comparing f2, comparing f3]
(For those not familiar with fold, the above expands to
comparing f1 `mappend` comparing f2 `mappend` comparing f3
which produces a function that can be applied to two Ds, to produce an Ordering.)
The defintion of compareD is so simple that it's obviously correct, and I wouldn't feel the need to unit test it even without static type checking.
Actually, the question may be even slightly more interesting than this, since I may not want to use just the standard <=> operator, but sort in different ways at different times, e.g.:
sortByOrderings :: [a -> a -> Ordering] -> [a] -> [a]
sortByOrderings = sortBy . foldl1 mappend
sortByF3F1 = sortByOrderings [comparing f3, comparing f1]
sortByF2F3 = sortByOrderings [comparing f2, comparing f3]
So, the questions:
What's the typical way of implementing this sort of thing in Ruby?
What's the nicest way of doing it using just what's defined in the standard libraries?
How close can one get to the Haskell code above, and how reliable is it, in comparison? If necessary, how can one ensure that the fields have a properly implemented <=> or < and > operators?
Incidently, while this is a Ruby question, I'm happy to consider discussion of the Haskell techniques on-topic if the elders of this site so agree. Please feel free to comment on whether that's appropriate or not and, if it is, tag this post 'haskell' as well.
Here's what I do to make custom sorting rules more manageable: on all my classes I ever need to sort, I define "to_sort" methods that return arrays, and then override <=> to use to_sort:
class Whatever
def to_sort
[#mainkey,#subkey,#subsubkey]
end
def <=>(o)
self.to_sort <=> o.to_sort
end
end
Thus sorting any array of Whatevers (including heterogeneous arrays of Whatevers and Whateverothers and Whathaveyours, all of which implement type-specific to_sort functions and this same <=> override) just devolves internally to sorting an array of arrays.
Here's a riff on your idea. It doesn't define any extra constants, allows you to use any combination of instance variables and methods to compare two objects, has early exit on not-equal, and includes all the methods defined by Comparable.
class Object
def self.compare_by(*symbols)
include Comparable
dispatchers = symbols.map do |symbol|
if symbol.to_s =~ /^#/
lambda { |o| o.instance_variable_get(symbol) }
else
lambda { |o| o.__send__(symbol) }
end
end
define_method('<=>') do |other|
dispatchers.inject(0) do |_,dispatcher|
comp = dispatcher[self] <=> dispatcher[other]
break comp if comp != 0
comp
end
end
end
end
class T
def initialize(name,f1,f2,f3)
#name,#f1, #f2, #f3 = name,f1, f2, f3;
end
def f1
puts "checking ##name's f1"
#f1
end
def f3
puts "checking ##name's f3"
#f3
end
compare_by :f1, :#f2, :f3
end
w = T.new('x',1,1,2)
x = T.new('x',1,2,3)
y = T.new('y',2,3,4)
z = T.new('z',2,3,5)
p w < x #=> checking x's f1
# checking x's f1
# true
p x == y #=> checking x's f1
# checking y's f1
# false
p y <= z #=> checking y's f1
# checking z's f1
# checking y's f3
# checking z's f3
# true
If you wanted, you could insert some extra error checking in there to make sure that
the values used to compare actually respond to <=> (using respond_to? '<=>'), and try to
give clearer error messages in the case wwhere they don't.
I took a similar approach as rampion, but wanted to handle the case where attributes could be nil.
module ComparableBy
def comparable_by(*attributes)
include Comparable
define_method(:<=>) do |other|
return if other.nil?
attributes.each do |attribute|
left = self.__send__(attribute)
right = other.__send__(attribute)
return -1 if left.nil?
return 1 if right.nil?
comparison = left <=> right
return comparison unless comparison == 0
end
return 0
end
end
end
Example Usage:
SomeObject = Struct.new(:a, :b, :c) do
extend ComparableBy
comparable_by :a, :b, :c
end
Well, here's a quick hack at an extension to Object to make this happen in what seems to be a reasonably nice way.
class Object
def self.spaceship_uses(*methods)
self.const_set(:SPACESHIP_USES, methods)
end
def <=>(o)
raise(NoMethodError, "undefined method `<=>' for #{self.inspect}") \
unless self.class.const_defined?(:SPACESHIP_USES)
self.class.const_get(:SPACESHIP_USES).each { |sym|
self.send(sym) < o.send(sym) && (return -1)
self.send(sym) > o.send(sym) && (return 1)
}
return 0
end
end
class T
def initialize(f1, f2) #f1, #f2 = f1, f2; end
attr_reader :f1, :f2
spaceship_uses :f1, :f2
end
This of course doesn't deal with any typing issues, to make sure that < and > are properly implemented for the objects returned by the methods in SPACESHIP_USES. But then gain, being Ruby, this is probably fine, isn't it?
Short comments can comment on this, but I'd be interested in seeing detailed discussion and extensions in other answers.
How do you deal with lambdas in boo? Is "callable" the same thing? How do you define a method that takes a lambda as a parameter?
Boo does support lambda expression syntax:
foo = {x|x+2}
seven = foo(5)
def TakeLambda(expr as callable(int) as int):
return expr(10)
twelve = TakeLambda(foo)
In this example, foo is a function that accepts a number x and returns x + 2. So calling foo(5) returns the number 7. TakeLambda is a function that accepts foo and evaluates it at 10.