This is an archive of the rejected RCRs from Ruby Garden. This archive is being made available as part of the transition to the new RCR process and archive at RCRchive.
Future rejected RCRs will be stored in sequence as an integral part of RCRchive.
class Msg
def initialize(name, type, txt)
@name, @type, @txt = name, type, txt
end
# ...
end
So, could we change parameter passing slightly so that if an instance method has a formal parameter starting with an '@' sign, the incoming value is assigned directly to the corresponding instance variable? Using this scheme I could write the above as:
class Msg
def initialize(@name, @type, @txt)
end
end
class Proc
def *(other)
raise unless arity == other.arity
proc {|*a| self.call(other.call(*a))}
end
end
and then, as a side-note being able to do:
f = lambda{|x| 2*x}
g = lambda{|x| x+1}
h = f * g
h.call 1 # => 4
Why not throw in some syntactic sugar for the "lambda{|x| ...}" stuff à la Haskells "x -> 2*x" while we're at it! Too vague; no actual mechanism proposed.
I think the poster may be talking about methods with implicit receivers. In that case you have more information on the methods it may call or not; but the poster doesn't take care of (or even mention) Object#method_missing, method-undef, forward references, and how his feature would interact with those.
I don't know what Perl's strict-subs have to do with it, I don't remember anything it did for me, and IIRC, strict-subs don't do anything when using Perl's method-lookup.
"hello #fred and barney"
With respect, you should think again. W3C wants XML to replace HTML, M$ is using XML as its data protocol in .NET, MacOSX uses XML for its config files. Beyond that all sorts of publishers and data providers are moving to XML or (XML compliant SGML) for preparation, tracking and publication. All the signs are that XML is going to be the data format (and markup language) of the 2000s-10s.
Where I work we have had to begin dealing with information being delivered in XML. Although its a perl shop, I have pursuaded the manager to let me use python for 'prototype development purposes'. Although I prefer ruby, the excellent XML support in python made the case for python arguable.
Absolutely! And what this means is that ruby must have acess to some parser, perhaps expat (but why not Xerces?), but most importantly of all the standard APIs (ie SAX and DOM) will need to be supported (though there is nothing wrong with having some unique ruby-xml API in addition the the standard ones).
<tag1 foo="bar">
<tag2 this="that"/>
<tag2 this="the other">mydata</tag2>
</tag1>
becomes:xmle.element_tag -> tag1
xmle.attr_foo -> bar
xmle.tag2[0].attr_this -> that
xmle.tag2[1].element_data -> mydata
xmle.tag2.count -> 2
xmle.tag2.each {|element| puts element.element_data} -> nil, mydata
Notice I preface the attributes of a tag with attr_ and the sub-tags with the actual name. The array index (tag[0]) is optional if there is only one. The xml element's direct data is element_data. Its worth trying to build this into some type of library to deal with XML that's Ruby flavored.What we should to is not to waste time using expat at all. We should use a professional quality XML parser. IMHO this should be Xerces (from xml.apache.org) because of MSXML's platform specificity and 'extensions' to the standard.
The approach taken with Perl, to create Xerces.pm, an API to Xerces-C (resulting in much faster parsing), would seem to be the obvious way to go.
Math::PI.times { puts "Hello" }
Complex::I.times { puts "Goodbye" }
%q{nesting {really} works}") and make the parser really just return literally what is written.
Maybe omit the detection of nested parenthesis that is possible in the other %-notations too
("%q{nesting {really} works}") and make the parser really just return literally what is written.
After seeing a million examples of overriding methods in classes by aliasing an existing method to something with a more obscure name, defining over that method and then calling the alias of the old method in the new method's code, I convinced myself there HAD to be a better way. In that vein, I've implemented the ability to "attach" an anonymous variable to a given method.
It works like this:
module MyStringComparison
def self.enabled
String.class_eval <<-'END'
old = instance_method(:<=>)
def <=>(other)
c1, c2 = [self, other].collect {|s|
s.gsub(/[^[:alnum:]]*/, '').upcase
}
method_var.bind(c1).call(c2)
end
define_method_var(:<=>, old)
END
begin
yield
ensure
String.class_eval <<-'END'
define_method(:<=>, method_var(:<=>))
END
end
end
end
irb(main):003:0> "Abc...?" <=> "A B C!"
1
irb(main):004:0> MyStringComparison::enabled {"Abc...?" <=> "A B C!"}
0
irb(main):005:0> "Abc...?" <=> "A B C!"
1
As you can see, not only does it leave the String class unchanged, it also does not provide any visible evidence of the : method being overridden, and the method overriding can be recursed without worrying about how exactly to do aliasing, defing, and undefing without conflicting upon names for old method storage.
Pretty simple and generalized, eh? :) You could essentially attach any variable you would like to a method in this fashion, but it's most useful for keeping an "anonymous" copy of the old method around. The implementation I came up with can be found here for Ruby 1.7.
Regarding the technical aspect of the proposed change, it increases the size of a NODE by one pointer, as well as the size of a FRAME. It shouldn't add any significant amount of overhead because of this, and remain invisible on benchmarks.
I'm not sure I have the hang of what the advantage would be of this over the aliasing approach. It seems to involve at least as many steps. I don't (yet) see why this way would be any easier, or make things easier to keep track of. Can you elaborate a little on that?
I don't think method_var covers exactly the same "problem space" as Ruby Behaviors, but there are certainly some points of contact, so perhaps some comparative remarks would be in order. With Behaviors, having to alias and unalias isn't an issue because the aliasing and unaliasing are done automatically. You design a Behavior, (such as one which redefines ), and the underlying engine takes care of swapping it in and out. Then in your top level code you invoke the behavior in a block.
For what it's worth, here's what you'd have to do to get a Ruby Behavior that did your string method change. ("ship" is the default alias for the spaceship operator :-)
module Behaviors
class Behavior
class BriansThing ",
(other)
c1, c2 = [self, other].collect {|s|
s.gsub(/[^[:alnum:]]*/, '').upcase
}
c1.ship(c2)
end
EOS
)
end
end
end
end
# Test
include Behaviors
b = Behavior.new(:BriansThing)
s = "Abc...?"
t = "A B C!"
p s t # => 1
b.adopt { p s t } # => 0
p s t # => 1
Anyway -- I'm not sure how to the point this is, but note that you get that same effect of a temporary change (but not without possible dangers... but that's another story), without having to explicitly save and restore, since the underlying Behavior engine does that for you.That should be:
p s t # => 1
b.adopt { p s t } # => 0
p s t # => 1
Solution only allows to bind one var to the method.
Can be fixed if everyone agrees not to set method_var directly, and that method_var is a pointer to the Method object representing that Method. Then you can add accessors to the Method, as you can do with Class objects.
It would work better if Methods were made more like "real objects"; that is, if there a 1-to-1 identity correspondence so that when you query for a specific method, you get always the *same* object. It would remove most of the nastiness associable with the solution I propose.
[]= is bang;
so
a version of []= that doesn't modify the receiver
would be cool.
1.1.
Array#set_at position, new_value
an_array.set_at(2, new_value)
and maybe
1.2.
Array#set_at!
or
1.3.
an_array.at(2) = new_value
# for example
"add a newline to the second and last item in the array"
an_array.each_index do |x|
new_val = an_array.at(x) + "n"
if (x == 2) or (x == (an_array.size - 1))
an_array.set_at(x,new_val)
end
end
or even:
an_array.each_index do |index,item|
or
an_array.collect |index,item|
if (index == 2) or (index == (an_array.size - 1))
item + "n"
else
item
end
end
These for example are describing examples of collect and collect!
in the Pickaxe Library Reference:
collect
a = ["a", "b", "c"]
a.collect {|x| x + "!" } -> ["a!", "b!", "c!"]
a -> ["a", "b", "c"]
collect!
a = ["a", "b", "c"]
a.collect! {|x| x + "!" } -> ["a!", "b!", "c!"]
a -> ["a!", "b!", "c!"]
The following is what I want to have as an additional, new method
for Arrays (for ease of use, convenience, and nicer code):
set_at
a = ["a", "b", "c"]
a.set_at 0,"x" -> ["x", "b", "c"]
a -> ["a", "b", "c"]
set_at!
a = ["a", "b", "c"]
a.set_at! 0,"x" -> ["x", "b", "c"]
a -> ["x", "b", "c"]
Tobi
As per my ruby-talk postings, I'm not sold on this. But in any case, I'd think a different name would be better. 'set', in any form, suggests that the receiver is going to set something.
Maybe: a = [1,2,3] a.with_at(0,100) => [100,2,3]
The code should not be all run together:
a = [1,2,3] a.with_at(0,100) # => [100,2,3]
David
Great! Thanks for your suggestion. My whish is to have that functionality for arrays; the name of the method is open for discussion. with_at position,new_value with_at! position, new_value or: (all with bang and non-bang versions): fill_at, place_at, value_at, at()=, at()!=, replace, set_at, ...
sorry, one in the listed doesn't make sense: at()!= maybe: at()= and at()=!
> an_array.each_index do |x| > new_val = an_array.at(x) + "n" > if (x == 2) or (x == (an_array.size - 1)) > an_array.set_at(x,new_val) > end > endWhat's wrong with the following?
an_array.dup.each_index do |x| an_array[x] += "n" if (x == 2) or (x == an_array.size - 1) endSorry, but I think that set_at or with_at would not be used that often to add it to the libs.
a.with_at(pos, val)would equal to
(b = a.dup)[pos] = val; bcorrect?
What I'd like to have is a collect_index or something alike. For me this would be much more useful, because it would let me ommit a counter variable.
Regards, Michael
> What's wrong with the following? > an_array.dup.each_index do |x| > an_array[x] += "n" if (x == 2) or (x == an_array.size - 1) > endOnly that the dup doesn't do anything :-) But Tobi's example seems to throw away the results of set_at, so it ends up as a no-op. Which doesn't in itself mean too much, but I still think that this isn't needed in the core language.
> a.with_at(pos, val) > > would equal to > > > (b = a.dup)[pos] = val; b > > correct?Yes.
> What I'd like to have is a collect_index or something > alike. For me this would be much > more useful, because it would let me ommit a counter > variable.I'd like that too -- so much so that I wrote it a few months ago :-)
module Enumerable
def map_with_indices
res = []
each_with_index do |e,i|
res.push yield e,i
end
res
end
end
map_with_indices would be a great addition to Ruby. (just hours ago I thought that collect_with_index would be cool; but I like your choice for the name much more) It should be available for arrays etc. and perhaps both bang and non-bang versions would make sense. Maybe you want to consider posting a new RCR for that?
... I still want a non-bang version of []=, which could look something like set_at(new_value, position) or with_at(new_value, position) (= this RCR is not obsolete; map_with_indices is a seperate request)
> What do you guys think?
I don't think Ruby core changes should be vote-based -- nor do I think they are likely to be :-) I tend to see it more as: people might use and exchange ideas, and based on their experience (qualitative and quantitative) decide whether an RCR is a good idea. Behaviors definitely have the potential to play a role in this, and to divert some of the RCR traffic.
I happen to think that map_with_indices actually should be a method of Enumerable, based on my own wanting to have it and talking with other people about it. Meanwhile I've got my own Behavior-friendly version :-)
map_with_indices map_with_indices!This could be added to Enumerable, and made available for arrays (etc.) I believe it would be a very handy method, that adds to Ruby's readability, conciseness and elegance. For example, it would obsolete the need for counters in certain operations.
res = []
ary.each_with_index {|e,i| res.push "#{i}: #{e}"}
you could do:
res = ary.map_with_index{...}
Dinky example, but I think it's a very useful method.
Also it would add symmetry to Enumerable. Though actually to be fully symmetrical (or whatever), we'd also need map_indices, which would be the map equivalent of each_index. (instead of (0...ary.size).map {|n|...})
Here's a running example, using an implementation of map_with_indices by David Black:
####################
# by David Black:
module Enumerable
def map_with_indices!
res = []
each_with_index do |e,i|
res.push yield e,i
end
replace res
end
def map_with_indices
dup.map_with_indices!
end
end
####################
a1 = ['zero','one','two','three']
a2 = ['zero','one','two','three','four','five']
# add a newline to the second and last element of any array
def my_format a
new_a = a.map_with_indices do |element,index|
if (index == 1) or (index == (a.size - 1))
element + "
"
else
element
end
end
end
a1_formatted = my_format a1
a2_formatted = my_format a2
p a1_formatted # -> ["zero", "one
", "two", "three
"]
p a2_formatted # -> ["zero", "one
", "two", "three", "four", "five
"]
Tobi
class Foo
def bar
puts "bar"
end
# Make bar visible only to MyClass
export :bar, MyClass
end
Could your database example be solved with the following code:
private
def foo
puts "foo!"
end
public
def bar
return self.method(:foo)
end
end
f = Foo.new
b = f.bar
b.call
class A
feature { ANY } -- Visible to all
value_of(other: A): INTEGER is
-- What is other's value?
do
Result := other.value
end -- value_of
feature { A } -- Visible only to A
value: INTEGER
end -- class A
This is highly trivial, but it should give a fair idea of what can be achieved with such a mechanism.
Here we basically give access to 'value' only to other objects of type 'A'.
This cannot be accomplished using the protected/private/public approach.I did not mean to imply that any object should be allowed to invoke bar() and get a reference to the private method foo. In a more realistic situation, bar() could check who the caller is (perhaps by requiring the caller to pass its binding as a parameter, then evaluating "self.type", or perhaps by passing in a key that only the calling class could possibly know). The reason for doing this in bar() instead of in foo() is because it is probably not a cheap operation, and so doing it only once is desirable.
The obvious disadvantage with this method is that it is not as clean as a real "export" feature.
Also, how do you propose to do the type checking? Since classes in Ruby are very dynamic, what is to stop someone from doing this:
class Database # repoen the Database class
def foo(databse_object)
database_object.exported_method()
end
end
There are a lot of places in Ruby where access control could certainly be done better, and other places where it is just plain broken. (I think this is the former case). So here's a question to whomever is reading: what can/should be done about the more general problem of fixing access control in Ruby?
useful.Array.new([1,2]) => [1,2]
Symbol.new should replace String#intern; the latter would only be kept for backwards compatibility.
Class.new and Module.new, when called with a block, should also call #module_eval with that block.
change Regexp#to_s so that it returns a string that gives back the first argument to Regexp.new (or equivalent).
add Regexp#options and Regexp#lang, which gives back Regexp.new's 2nd and 3rd arguments.
Given:
1 < x < 5
If 1<x is false, then what does it mean to have:
false < 5
If this is guarantee to be false, then would:
false>= 5always be true? In that case, what happens with:
1>= x>= 5if 1>=x is false?
I think making this change introduces a lot of problems, and the "C way" of writing such expressions is not too terribly difficult to read.
BTW, Rubygarden's translation of &lt; and &gt; into < and > makes it difficult to type messages like this.
false because it would short-circuit at the first failure, much like(1 already does.
I asked about this on the mailing list once, and was referred to matju's Hollow* classes (in the MetaRuby package). Unfortunately, they enforce some constraints on their implementation that are inconsistant with the built-in Array and Hash classes.
keys() defined would give you similar leverage to have each() defined. Modules Enumerable and Keyable, perhaps?.[1,2].map(:succ) #=> [2,3]I know that you can do it with
[1,2].map {|e| e.succ}
but its more than a "shortcut". IMHO its more in line with how map is used in functional programming languages.
I we want to be really fancy we could also allow methods as parameters. But maybe that's taking it too far.
I'm not sure what should happen if one both gives a parameter and a block. Either skip the parameter or apply it first? Probably the latter since you would otherwise not specify the parameter.
So here's the new semantics I'm asking for (I'm not sure about the extra args but added them anyway):
class Array
def rcr50_map(symbol = nil, *args, &block)
if symbol.kind_of?(Symbol)
a = self.map {|e| e.send(symbol, *args)}
else
a = self
end
a.map(&block)
end
end
Oh, it should really be Enumerable#map but this is just an example!?Just a suggestion for an alternative method name:
[1,2].map_with(:succ) #=> [2,3]
[1,2].map(:succ) #=> [2,3]I'd write
[1,2].map(&:succ) #=> [2,3]Of course this would require a parser change and I doubt it will be done, but it would have two advantages:
[1,2].map(&:+, 4) #=> [5,6]
apply?
class String
def upcased?
if self.upcase == self
return true
else
return false
end
end
def downcased?
if self.downcase == self
return true
else
return false
end
end
def capitalized?
if self.capitalize == self
return true
else
return false
end
end
end
class String
def upcased?
self.upcase == self
end
def downcased?
self.downcase == self
end
def capitalized?
self.capitalize == self
end
end
attr_initializer :foo, :bar
This can be done by adding it as a method to Module, just like attr_accessor and similar methods.
class X
attr_initializer :foo, :doo, :bar
...
end
basically expands to:
class X
def initialize(foo, doo, bar)
@foo, @doo, @bar = foo, doo, bar
end
...
end
( More info in [ruby-talk:23768] )
class X
def initialize(@foo, @doo, bla, @bar)
@bla=bla.to_f
end
endThis would be same as:
class X
def initialize(foo, doo, bla, bar)
@foo=foo; @doo=doo; @bar=bar
@bla=bla.to_f
end
end
and this has benefit of having standard initialize too.
class X
def initialize(@foo, @doo, bla, @bar)
@bla=bla.to_f
end
end
I just don't think that looks good or is easily understandable. It uses two different styles/mechanisms to do the initialization.
However, some argue that you should be able to do (for any method, not only initialize): def anymethod(@foo) and then have the instance_variable @foo be assigned directly, simply because it is consistent with blocks as in { |@foo| ... } I can sympathize with that but I think it's a different issue. I also don't find the initializer written as above particularly clear and wouldn't like to write them that way. In that case I prefer writing out an intitialize like it is today. It just doesn't resonate with me, but of course people have different tastes.
To the second poster, I don't agree that a shortcut must be fully flexible. attr_initializer should surely not take a block, just like attr_accessor does not! If you need that, instead use the standard method.
Consider that also attr_accessor, attr_reader, attr_writer are shortcuts for a common case and therefore they are useful, but there are still times when you need to define your own accessor methods too, like if you want to put constraints on the values, do bounds checking, or to let the getter return a different type than you use internally. In all these cases you fall back to the standard method and the case is the same here. It is clear attr_initializer does not, for example, allow you to add default values. It's not meant to solve every case.
Let's make one thing clear, a shortcut like this, also attr_accessor, is not meant to replace but to extend. It allows you to define the function manually if you want or when you need to.
Consider most other RCRs that suggest to add a fairly specialized method to some class just for completeness, and people often seem to think that's a good idea. But additions should be made only for commonly used things. For me, the above initialize is very common for simpler container-type classes. For others I need to use a full def initialize(). I think RCRs should be rejected if they are not common enough, to avoid growing the language too much, and you are free to do so if you wish.
But you find attr_accessor useful, don't you? Then attr_initializer could be useful too. But not for everyone perhaps. It's just a suggestion and you need to decide if it is worthwhile for you or not. Whether to allow def meth(@var) or not is another question. In fact, I would still find attr_initializer useful regardless. To all readers - if you are reading RCRs, please vote, even if you specify that you don't really care.
The idea is: allow a second argument to Dir.glob (aka Dir.[]), that argument being used as a filter, passing everything returned by the glob through Kernel#test.
Example: Dir.glob("*.rb", "f") (returns all *.rb that match test("f", name)) Implementation:
class << Dir
alias :oldglob :glob
def glob(g,t=nil)
d = oldglob(g)
if t
d.find_all {|e| test(t,e)}
else
d
end
end
end
(P.S. There seem to be extra blank lines being put in here but I'm not using Opera this time :-)
s = "a foo and a bar" re = /a (f.*?o) and a (b.*?r) to/ foo, bar = s[re] puts foo,bar # -> foo bar
As a side note, I think your regex is a bit messed up (since f.*?o matches "fo", then none of the rest of the regex matches; I'm not sure where the "to" part is supposed to fit in).
a, b = foo.match(/(bar).*(baz)/)
No one showed much interest. I like either of s[re] or s.match(re) better than:
dummy, a, b = /(bar).*(baz)/.match(foo).to_a
or
a, b = [ $1, $2 ] if foo =~ /(bar).*(baz)/
Actually, I think I may like yours better, fewer characters :->
---------------------------------------------------------------------- | Jim Hranicky, Senior SysAdmin UF/CISE Department | | E314D CSE Building Phone (352) 392-1499 | | jfh@cise.ufl.edu http://www.cise.ufl.edu/~jfh | ----------------------------------------------------------------------
a, b = foo.match(/(bar).*(baz)/)"is a generalization of the existing mechanism", because the existing mechanism is that match returns a MatchData object.
I don't think it's so bad to do:
a,b = /(hel).*(ere)/.match("hello there")[1..-1]
(note: no "to_a")
It changes functionality. Presently, this is what happens:
irb(main):001:0> s = "foo and bar" "foo and bar" irb(main):002:0> s[/(foo).*(bar)/] "foo and bar"
If I understand correctly, then this is what you suggest:
irb(main):001:0> s = "foo and bar" "foo and bar" irb(main):002:0> s[/(foo).*(bar)/] [ "foo", "bar" ]
Why would the String#[] return an string in almost all cases, but an array of strings in one oddball case? (Yes, I know that aString[aFixnum] -> aFixnum is already an exception).
BTW, could someone please fix the HTML filter to not change &gt; to > when I click "preview"?
After all, POLS and HOOP are the main
philosophies driving Ruby, if I'm not
mistaken, and having String#match feels
to me to be less suprising and more human
oriented than not having it, especially
when there's a String#gsub.
It seems I'm in the minority, though.
For example:
str = "I say: Hello there to you" re = /(Hel).*?(ere)/ str[re] # => "Hello there"would have to be rewritten in a less concise manner.
Every method that used String#[] with, say, a regex passed in as an argument, would now have to examine the regex, and/or branch on the type of the return value of [], etc....
I agree that having to examine MatchData objects can be a bit cumbersome. But in a sense you're suggesting that a similar examination process be conducted on the return value of String#[], instead of on a MatchData object -- plus introducing an inconsistency in the method's behavior.
float x = 3/2;
printf("%fn", x);
puts 3.0/2.0So what? C is a low level language...
C being low-level and Ruby being high-level isn't the issue. Ruby is dynamically typed, and it's perfectly legal for you to pass integers into a function that is expecting floats. Adding an integer division operator does not solve this problem.
Incidentally, Ruby is written in C, and Ruby extensions are written in C. That's not an insignificant argument for maintaining some coherence between the two languages.
...but if x and y happened to not become Float in the preceding code, you get a bogus answer.
This is definitely a problem with dynamically-typed languages, and extends far beyond just division. If I have a function that expects a String and I pass it an Array, then what should that function do? Note that C++ has a similar problem with templates:
template<typename T, typename U>
float foo(T t, U u) {
return t / u;
}
...
std::cout << foo(3, 2) << std::endl;
Should we remove binary - since we can just combine binary + and unary - instead? Maybe += needlessly complicates the language as well.
The operators you mentioned do not carry type information with them. An integer division operator and a floating-point division operator both carry type information. That is why they seem to not match Ruby philosophy.
>4) I suspect that for the work you are doing, Ruby is probably not the right solution for the job. A language better suited to floating-point calculations will probably perform much better (i.e. be faster and more accurate).
Is that because you assume that I want to type 2/3 at my program? I'm extracting certan features from XML files and calculating the probability of finding certain features in future files...
No, I'm suggesting that you use a different language, because:
...I have a lot of
prob = feature_count / total.to_f
So why not convert your data to floats when you read them in from your xml file? That seems to me to be the simplest solution.
If you really want Fixnum#/ to do floating-point division in spite of all this, then one of the beautiful things about Ruby is that you CAN make this happen:
class Fixnum
def /(other)
p self
p other
end
end
3 / 2 # will print 3, then 2, then return nil
In order to keep this from interfering with Ruby code that you didn't write, you may want to consider using something like Ruby Behaviors to limit the scope of the change.
C being low-level and Ruby being high-level isn't the issue.
I think it is. A high-level language ought to allow me to think about numbers instead of int, long, float, double. Saying that it shouldn't do that is in my opinion equivalent to saying it shouldn't have lists. Out in the world, when I divide two of those things called `numbers', I sometimes get a result with a decimal point in it. I don't care whether the `numbers' already had decimal points in them or not.
So why not convert your data to floats when you read them in from your xml file?
A perfectly reasonable question, except that I'm not reading values from the XML, I'm counting the occurance of certain values. Although as I said, this particular program is irrelavent (for one thing it is already written and running), it long ago occurred to me that I could just initialize values to float, like:
feature_count = 0.0 [...] feature_count += 1 if feature(doc) [...] prob = feature_count / totalbut think for a second what that conveys to someone reading the code. Why am I doing that? Since the value is a count, perhaps they should change it to
0 to improve efficiency. Or maybe I should mark my code with comments like:
# Don't change this or else Ruby will # do integer division later on. x = 0.0As ugly as I think using
.to_f is, at least it puts the explicit conversion with the division instead of some random amount of code before it.
In a final attempt to be clear, I don't have any major problem with telling Ruby what I mean using .to_f, I'm concerned with telling humans what I mean. Which is why I want to use Ruby in the first place. And when I say ``want to use'', I mean in general. The specific program in question has long-since been written with copious and ugly .to_f's.
Ruby is an interpreted language, and is slower than an equivalent solution in a compiled language.
Ruby isn't just a slower language, from the language shootout it appears to be just about the slowest language. If that was my primary concern, I wouldn't be using it.
A Ruby solution for a program that must process large amounts of data will probably have many pieces implemented as a C extension in order to be efficient.
Lucky me, an interface to a fast XML parser is already there. You might want to look up REXMLBuilder for your own reference.
If you really want Fixnum#/ to do floating-point division in spite of all this, then one of the beautiful things about Ruby is that you CAN make this happen:
I don't claim to be a Ruby expert, but I have been using it for some time now, have prototyped a simple fulltext search engine and Bayesian classifier in it (calculating probabilities, get it?) and I think you can assume I'm familiar with the simplest concepts of the language which you chose to demonstrate. I don't do what you suggest because that is even worse for people reading the code.
Meanwhile, nobody has mentioned why it is so important to have integer division as the default. The closest you've come is to say that it's not an insignificant argument to say Ruby should be like C. Yet you seem to be so opposed to it that you'd rather I use a different language than advocate that Ruby compute a floating point value when dividing integers. So what exactly is the problem with:
3 / 2 #=> 1.5 (3 / 2).to_i #=> 1? Do you have a language-design argument for why this would be undesireable? Does it go something like ``but, well, the arguments are integers''? Should I then count for you the number of built-in methods that return a type different from their arguments?
It's even easy to implement without much overhead, since Ruby already calculates the remainder when it sees 3/2 only to throw it away later. If the remainer is 0, return, otherwise redo as a floating point divide.
My argument is that this way conveys more information and is more clear to humans reading the code than any method you care to name for guaranteeing floating point division using the current semantics. If you do manage to name a method that is equally informative and clear, I'll gladly use it.
You also haven't answered my question about 2 / 3.0. Is your only argument for why this should be a floating point division that C does it that way? It sure looks equally like an integer division to me.
x/y, they know which kind of division they want. I can't think of any algorithm that would require dynamic selection of the division operator. If fact, if you can't guarantee the type of x and y, then every time you divide, you must write eitherI suspect there is a lot of code out there that inappropriately assumes it always gets integers when doing division. That seems dangerous. That's why I see this as a correctness issue.
x.to_i / y.to_i # to get truncating division
or
x.to_f / y # to get non-truncating division
If fact, if you can't guarantee the type of x and y, then every time you divide, you must write either [...]
Exactly. And I like the terms truncating and non-truncating division that you use because it shows that adding new operators does not mean that they somehow carry type information, it should be perfectly reasonable to use truncating division with floats.
I think the main question to answer is ``What is the common case?''. If you add a method called quotient, how likely is it that there will be a module to alias / to quotient, which almost all programs will end up requiring? If it is very likely, then the name for quotient should be /, and instead of quotient there should be truncated_quotient and a module that aliases / to that.
That is assuming that breaking existing programs until they add require 'integer' or something is acceptable.
As long as there is some reasonably fast method that is a guaranteed non-truncating division, I'll be much happier, although all my programs will end up aliasing / to whatever it is.
1. Where will this method be defined?Each numeric class, like other numerical operators.
2. How will it handle new numeric types? (suppose I add a BigFloat type)By coerce system, like other numerical operators.
3. How will you determine what kind of division is required?I'm not sure what you mean. If you want precise division, use the new method, otherwise use '/'.
4. If it is determined by a parameter, then would it be reasonable to divide this one giant method into many smaller methods?We chose coerce system for numeric type mix. It's done before this division discussion.
I think the main question to answer is ``What is the common case?''.It depends person to person, program to program. I myself have almost never used int/int -> float division. I guess this kind of problem should be solved by selector namespace or similar technology.
I'm not sure what you mean. If you want precise division, use the new method, otherwise use '/'.
Your original statement was that you would add "a new method for more accurate division, that returns most accurate division (Float by default, Rational if you require 'rational')." My question is how you would determine what the most accurate division is (particularly for and between user-define numeric types).
BTW (slightly off-topic), is there anything happening in Ruby with regard to double dispatching? Would this be useful here?
Your original statement was that you would add "a new method for more accurate division, that returns most accurate division (Float by default, Rational if you require 'rational')." My question is how you would determine what the most accurate division is (particularly for and between user-define numeric types).
7/3
gives the rational number 7/3, while7 .div 3
gives 2 (C-like integer division), and7 .divmod 3
gives [2, 1] (integer division with remainder).Rather than needing an RCR, I think this issue could be addressed by popularizing the mathn standard library (which is not mentioned in the pickaxe book or the bezoar-goat book).
Regards, oinkoink (I haven't yet figured out how to put my name in the header!)2/3 == 0.666..and I don't feel like changing to a different language if I only need to make a couple of quick calculations. Take for example the current implementation of the Matrix#inv method, as implemented in the standard library 'matrix'. Right now, because of this IMHO weird semantics of :/, you get
require 'matrix' p Matrix[[2.0, 3], [3, 4]].inv #=> Matrix[[-4.0, 3.0], [3.0, -2.0]] p Matrix[[2, 3], [3, 4]].inv #=> Matrix[[1, -1], [-1, 1]]Not that is a big issue, but this type of "dynamic behavior" gives probably every mathematician a big grin.
From what I can tell, require 'mathn' satisfies me.
I'd still be happier if it was the default behavior, but I'll live.
It is definitely the case that mathn needs more publicity.
Comments
Possible reason for the rejection. (HughSasse, 2001-08-02 06:50:45)
Reason for rejection