[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Reason #642 to use Ruby instead of C++ -Carpal Tunnel Syndrome

ptkwt

11/15/2003 6:59:00 AM


Seems like things are a bit slow on the list these days, so here's a
little rant...

I'm taking a class on layout algorithms (layout of wires on a chip). Most
of these tend to be graph algorithms. One of the assignments is to
implement the Kernighan-Lin partitioning algorithm; and it must be
implemented in C/C++. Now there's really no good reason why it has to be
in C++ other than maybe that's all the instructor knows how to read. So of
course I prototyped it in Ruby first - took about 2 hours to
implement in Ruby including debugging the algorithm and testing. Now I
kind of thought, "Hey, I finished this thing three weeks early in
Ruby why not ask the prof if he'd be willing to accept it in Ruby since
it's so early?". Of course he said it _wasn't_ alright and I'd be ding'ed
one letter grade if it's not in C or C++.

So I dug out my Stroustoup and another book on STL. Took me about three
hours just to get the file parsing part of it working (a simple CSV
format). And I've been working on the algorithm part for the last day and
a half; it's almost done, but it probably needs at least 2 or 3 more hours
of work.

Of course the file parsing part in Ruby was just:

adj_hash = {}
tmp_hash = {}
IO.foreach(filename) {|line|
node,*adj_nodes = line.split(',').map{|n|
unless tmp_hash.has_key? n.strip
tmp_hash[n.strip] = Graph::Graph::Node.new(n.strip)
else
tmp_hash[n.strip]
end
}

That's just 10 lines. I won't post the C++ abomination for accomplishing
the same thing here, let's just say that it's 45 lines long.

Of course the algorithm has to do a lot of iteration over containers
(sets), stuff like (in Ruby):

b.each {|n|
if adj_hsh[node].include? n
external_cost += 1
end
}

Five lines in Ruby. In C++:

for(LI n=b.begin();n!=b.end();++n)
{
if(_adj_map[node].find(*n) != _adj_map[node].end())
{
external_cost++;
}
}

Seven lines in C++ (8 if you include the typedef for the set iterator,
LI). OK, that's not that many more lines, but there
certainly are a lot more characters to type and it's nowhere near as
comprehensible.

Oh, my aching wrists!

....rant over.

Phil
5 Answers

Niklas Frykholm

11/17/2003 9:37:00 AM

0

> Of course the file parsing part in Ruby was just:
>
> adj_hash = {}
> tmp_hash = {}
> IO.foreach(filename) {|line|
> node,*adj_nodes = line.split(',').map{|n|
> unless tmp_hash.has_key? n.strip
> tmp_hash[n.strip] = Graph::Graph::Node.new(n.strip)
> else
> tmp_hash[n.strip]
> end
> }
>
> That's just 10 lines. I won't post the C++ abomination for accomplishing
> the same thing here, let's just say that it's 45 lines long.

I love Ruby's structure and convenience functions so much, I often try
to mirror them in C++. For example:

void split( std::vector<std::string>* results, const std::string& s,
const std::string &split_by)
{
std::string::size_type start = 0;
while(1) {
std::string::size_type found = s.find(split_by, start);
if (found != start)
results->push_back( s.substr(start, found - start) );
if (found == std::string::npos)
break;
start = found + split_by.size();
}
}

It's a bit extra work to write such general functions, but think how
much easier it will be the next time you want to move some code from
Ruby to C++.

// Niklas

Josef 'Jupp' Schugt

11/17/2003 9:47:00 PM

0

Hi!

* Phil Tomson; 2003-11-17, 14:21 UTC:
> b.each {|n|
> if adj_hsh[node].include? n
> external_cost += 1
> end
> }
>
> Five lines in Ruby. In C++:
>
> for(LI n=b.begin();n!=b.end();++n)
> {
> if(_adj_map[node].find(*n) != _adj_map[node].end())
> {
> external_cost++;
> }
> }

Now that is *really unfair. Following an alternative scheme of
writing C(++) programs that are only five lines.

for(LI n=b.begin(); n != b.end(); ++n) {
if(_adj_map[node].find(*n) != _adj_map[node].end()) {
external_cost++;
}
}

I almost always write my C code like that. Note that one can save
even more lines and write

for(LI n=b.begin(); n != b.end(); ++n)
if(_adj_map[node].find(*n) != _adj_map[node].end())
external_cost++;

The essential mistake is counting lines. What one should count is the
number of characters.

Josef 'Jupp' Schugt
--
.-------.
message > 100 kB? / | |
sender = spammer? / | R.I.P.|
text = spam? / ___| |___


Martin Weber

11/17/2003 10:04:00 PM

0

On Tue, Nov 18, 2003 at 06:47:00AM +0900, Josef 'Jupp' SCHUGT wrote:
> (...)
> The essential mistake is counting lines. What one should count is the
> number of characters.

Sure.

for (LI n=b.begin(); n != b.end(); ++n)
if (_a[nd].find(*n) != _a[nd].end())
ec++;

The essential mistake is trying to count something. Go feel & figure.

-Martin


Mauricio Fernández

11/18/2003 6:39:00 PM

0

On Tue, Nov 18, 2003 at 07:04:19AM +0900, Martin Weber wrote:
> On Tue, Nov 18, 2003 at 06:47:00AM +0900, Josef 'Jupp' SCHUGT wrote:
> > (...)
> > The essential mistake is counting lines. What one should count is the
> > number of characters.
>
> Sure.
>
> for (LI n=b.begin(); n != b.end(); ++n)
> if (_a[nd].find(*n) != _a[nd].end())
> ec++;
>
> The essential mistake is trying to count something. Go feel & figure.

Somebody proposed the number of tokens as quite a reasonable measurement,
to be taken with a grain of salt as all metrics.

--
_ _
| |__ __ _| |_ ___ _ __ ___ __ _ _ __
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Not only Guinness - Linux is good for you, too.
-- Banzai on IRC

ptkwt

11/19/2003 7:24:00 AM

0

In article <20031118183857.GB18667@student.ei.uni-stuttgart.de>,
Mauricio Fernández <batsman.geo@yahoo.com> wrote:
>On Tue, Nov 18, 2003 at 07:04:19AM +0900, Martin Weber wrote:
>> On Tue, Nov 18, 2003 at 06:47:00AM +0900, Josef 'Jupp' SCHUGT wrote:
>> > (...)
>> > The essential mistake is counting lines. What one should count is the
>> > number of characters.
>>
>> Sure.
>>
>> for (LI n=b.begin(); n != b.end(); ++n)
>> if (_a[nd].find(*n) != _a[nd].end())
>> ec++;
>>
>> The essential mistake is trying to count something. Go feel & figure.
>
>Somebody proposed the number of tokens as quite a reasonable measurement,
>to be taken with a grain of salt as all metrics.
>

And as I mentioned in the original post, the Ruby snippet is much more
'comprensible' (readable?) at a glance than the C++ one.

And just to introduce another measure: productivity. I did the original
Ruby prototype in 2 hours (including debugging the algorithm) and then set
out to 'translate' it to C++. It took me a couple of days (well,
probably about 10 to 12 hours total) to get it all working in C++. Now,
sure, I don't program in C++ every day so I might be a bit rusty, but
even if I double my C++ productivity, I'd still be more than 2 to 3X more
productive in Ruby.

Phil