Ruby wish-list

On Thu, Jun 26, 2008 at 1:00 AM, Roger P. [email protected]
wrote:

Yeah /* comments / would be sweet. Then you could also have ‘inline’
comments, like
a = [8…9 /
bread id’s /, 900…990 / butter id’s */]

Déjà vu?
a = [ 8…9 || “bread id’s”, 900…990 || “butter id’s”]

Which would be awesome in some instances. Obviously these are poor
examples, but with some it would be nice.
And my technique just makes it clear how poor they are IMHO.
Robert


http://ruby-smalltalk.blogspot.com/

There’s no one thing that’s true. It’s all true.

Joel VanderWerf wrote:

The check for garbage can’t be done concurrently with ruby code:

a = []
$a = a
a = nil

depending on how the gc process is scheduled, that empty array may
falsely appear to be garbage:

start scan * SNAPSHOT *

a = []

scan globals

$a = a
a = nil

scan locals

Definitely a consideration.

Do you think this help? The child process is basically operating off a
snapshot of memory, since it was a fork. It will thus only ‘mark as
free’ the ruby objects that are inaccessible at the time of the
snapshot, thus, in this example, not collecting “a” since it…hasn’t
been created yet.

The memory is ‘reclaimed’ by the parent “all at once” so should avoid
concurrency weirdness that way, too. There is always “at most” one fork
doing a GC. Come to think of it, I’m not sure how this would work if
you had a process that actually called fork while running, but for
single [true] threaded scripts it should work.

Thoughts?

-R

Roger P. wrote:

start scan * SNAPSHOT *

free’ the ruby objects that are inaccessible at the time of the

-R

Oh, I wasn’t understanding your idea, which does seem to make sense now.
There’s the overhead of essentially duplicating the object space of the
original process in the fork (since mark will write to memory pages).
Maybe it would be worth this cost (esp. on a second processor) for the
benefit of not having to stop the main process?

Interesting!

John J. wrote:

On Oct 19, 2007, at 5:09 PM, Roger P. wrote:

Roger P. wrote:
if arr.include? ‘a’
puts “array arr includes the letter ‘a’”
end

Another wish [I believe this one is in facets already] is that wherever
there’s a multiples verb like .include? it would also come with
.includes? version so that the grammar isn’t as confusing.
Thanks!
-R

Joel VanderWerf wrote:

start scan * SNAPSHOT *

Oh, I wasn’t understanding your idea, which does seem to make sense now.
There’s the overhead of essentially duplicating the object space of the
original process in the fork (since mark will write to memory pages).
Maybe it would be worth this cost (esp. on a second processor) for the
benefit of not having to stop the main process?

Now that you mention it, this might would work even better in
conjunction with Hongli’s Copy on write friendly GC. Then you wouldn’t
have to copy the entire ruby space per GC :slight_smile:

Interesting!

I can’t get much credit for the idea since it just came to me while
reading scriptures yesterday morning :stuck_out_tongue:
Now you know what distracts me a lot.

I’ll probably hack it up sometime, first version as a straight patch to
1.8.6

-R

On Aug 7, 11:17 pm, Roger P. [email protected] wrote:

Another wish [I believe this one is in facets already] is that wherever
there’s a multiples verb like .include? it would also come with
includes? version so that the grammar isn’t as confusing.
Thanks!
-R

My interpretation of it is that “include” here is in the infinitive,
as in “Does x include y?”, so the API as it is makes sense to me.
YMMV, of course.

AdSR

there’s a multiples verb like .include? it would also come with
includes? version so that the grammar isn’t as confusing.
Thanks!
-R

My interpretation of it is that “include” here is in the infinitive,
as in “Does x include y?”, so the API as it is makes sense to me.
YMMV, of course.

Yeah both would be good.

From my side

if a.includes? b …

works nicely.

-R

On 8/8/08, Mikael Høilund [email protected] wrote:

Perhaps a bit controversial, but I’d like to see a keyword for the “current
block” as a way to refer to the Proc instance created inside that block.
That would allow for recursive anonymous blocks like:

[[1,2,[3]],[[[5],6],7],8].map { |e|
Array === e ? e.map(&current_block) : e.to_s
}

It’s not exactly the same, but couldn’t you just define a
recursive map function?

class Array
def map_r &block
map{|e|Array===e ? e.map_r(&block) : block[e]}
end
end
p [[1,2,[3]],[[[5],6],7],8].map_r{|e|e.to_s}

=> [[“1”, “2”, [“3”]], [[[“5”], “6”], “7”], “8”]

Mikael Høilund wrote:

[[1,2,[3]],[[[5],6],7],8].map &(deep_to_s = proc { |e|
Array === e ? e.map(&deep_to_s) : e.to_s
})

IIUC, this would also let us take this idiom:

pr = proc {|h,k| h[k] = Hash.new(&pr)}
h = Hash.new(&pr)
h[1][2][3] = 6
p h # ==> {1=>{2=>{3=>6}}}

and simplify to:

h = Hash.new {|h,k| h[k] = Hash.new(&current_block)}

On Aug 8, 2008, at 20:19, Adam S. wrote:

=> [[“1”, “2”, [“3”]], [[[“5”], “6”], “7”], “8”]

That’s not optimal if it’s just for a single usage, especially not if
it requires monkey-patching a built-in class. I could imagine this
being used pretty much any time recursive behavior is necessary for an
iterator. And besides, what’s more descriptive?

array.map { |e|
Array === e ? e.map(&current_block) : e.to_s
}

or

array.map_r { |e| e.to_s } # Please look somewhere in the source tree
for the definition of Array#map_r

?

On Aug 8, 2008, at 21:30, Joel VanderWerf wrote:

IIUC, this would also let us take this idiom:

pr = proc {|h,k| h[k] = Hash.new(&pr)}
h = Hash.new(&pr)
h[1][2][3] = 6
p h # ==> {1=>{2=>{3=>6}}}

It’s dangerous to go alone. Until we have this sort of divine magic,
take this:

h = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
h[:a][:b][:c] = :o
h
=> {:b=>{:c=>:o}}

Perhaps a bit controversial, but I’d like to see a keyword for the
“current block” as a way to refer to the Proc instance created inside
that block. That would allow for recursive anonymous blocks like:

[[1,2,[3]],[[[5],6],7],8].map { |e|
Array === e ? e.map(&current_block) : e.to_s
}

without resorting to ugly syntax like

[[1,2,[3]],[[[5],6],7],8].map &(deep_to_s = proc { |e|
Array === e ? e.map(&deep_to_s) : e.to_s
})


instance_variable_set(%@@%sample@%%@ew@.succ, Class.new(&proc{def
self.net;$;,
$/=‘’,‘/’;%;.fqn-
cmtkhng;end}));Kernel.send(:“define_method”,:method_missing){|
n,$|$<<“?kd!jhl”;n=split.map{|q|q.succ}‘’;puts n.reverse.chomp.tr(
%w{" a})}
[email protected]

Rubbing the lamp…
I wish…

a = [1,2,3,4]

a[0…1, 4]

or

a[1,2,3]

worked.

:slight_smile:
-=R

A thought on current_block_yield and then the GC:

It’s not exactly the same, but couldn’t you just define a
recursive map function?

class Array
def map_r &block
map{|e|Array===e ? e.map_r(&block) : block[e]}
end
end
p [[1,2,[3]],[[[5],6],7],8].map_r{|e|e.to_s}

=> [[“1”, “2”, [“3”]], [[[“5”], “6”], “7”], “8”]

Though a little hackish, I wonder if you can receive a named block then
pass that block to itself, a la
def map_r &block
map{|e| block(e, &block) }
end
so that the block could itself call yield. But this would still be a
little harder than being able to say current_block, should it be doable.
Just thinking out loud.

A question on the GC.
So if you try and build a multi-threaded GC [one thread picks up on free
objects, hands them back to the parent thread for use], it turns out
that if you don’t free memory, then my current GC does this:

  1. you run out of freelist, so you call garbage_collect which spawns a
    child thread, and adds to the heap so the parent can continue.
  2. when the child thread terminates the heap is now in a larger state
    than it was.
  3. when it runs out of freelist again, it adds to the heap and spawns
    the child thread. The child thread now takes longer to finish than it
    did before. Meaning the parent will be adding more to heap while
    waiting for it to finish.
  4. repeat 3 over and over until you run out of memory.

So currently it doesn’t free any memory ever [commented it out]. I’m
hoping that adding that capability will do the trick. If that doesn’t
work, though, it seems possible for these two threads to become engaged
in a cycle, if you ever get above a certain threshold then basically it
will just eat up all the memory in the system as it takes longer and
longer to collect. So it exacerbates the problem.

Potential ways to beat this: never add to the heap during a garbage
collect?

Thoughts?
Thanks!
-R

Oh, I wasn’t understanding your idea, which does seem to make sense now.
There’s the overhead of essentially duplicating the object space of the
original process in the fork (since mark will write to memory pages).
Maybe it would be worth this cost (esp. on a second processor) for the
benefit of not having to stop the main process?

I’ll probably hack it up sometime, first version as a straight patch to
1.8.6

Turns out that just increasing the malloc limit to 80MB or so gives a
nice decrease in GC time[1]–about 80% for me. So that’s an easy stop
gap till I get this going. It does tend to use a lot more RAM, though,
unfortunately.

Question about typical VPN’s: I assume that typically the bottleneck is
typically RAM and not CPU [ex: on 256MB slice], and they have access to
multiple cores where available, is that right?
Thanks!
-=R
[1] http://github.com/skaes/railsbench/tree/v0.8.3/GCPATCH

Assuming you mean Range#to_a (i.e. an instance rather that class
method) I don’t think it’s becoming obsolete.

It throws warnings as deprecated, for some reason.

I don’t think so:

shadowfax:~/Documents/terralien/dltsolutions/enrollnow rick$ ruby1.9 -v
ruby 1.9.0 (2007-10-25 patchlevel 0) [i686-darwin8.10.2]
shadowfax:~/Documents/terralien/dltsolutions/enrollnow rick$ ruby1.9
-we ‘(1…3).to_a’

Ahh I get it. Odd

S.find 1…6.to_a
(irb):19: warning: default `to_a’ will be obsolete

I was confusing that for

S.find (1…6).to_a

which works as expected. Thanks for helping me figure that out. I have
no idea why 1…6.to_a doesn’t raise an exception. Oh well.
Thanks.
-=R

On Aug 14, 2:35 pm, Roger P. [email protected] wrote:

worked.

Two things:

  1. In my mind, this general thread is somewhat ridiculous. It’s been
    going on for – what is it? – ten months now? It seems to be just a
    laundry list for things you want Ruby to do, whether they’re sensible
    or not, without a lot of thought into them, and at least sometimes
    with reasoning like “I’m lazy and don’t want to type some brackets”.

  2. “I wish X worked” is not a very useful way to describe what should
    happen. I’m not saying you have to write tests or specs, but do
    describe the behavior you expect. Maybe looking at the RubySpec
    project will give you an idea of everything Ruby presently “should do”
    and what the other implementations are working towards. If that
    doesn’t get you going, think about it as contributing to Rubinius in
    some way, and the sooner that comes out the sooner you can easily
    twist even more of Ruby to your desires.

When you’re working on describing the behavior, consider this (from an
irb session in Ruby 1.8.6):

arr = (1…10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
arr[3,4]
=> [4, 5, 6, 7]

You seem to want arr[3,4] to return [4,5], and guess what? There’s a
way to do that now:

arr.values_at(3,4)
=> [4, 5]

Let’s say you don’t care for Array#values_at and Array#[] is changed
to work as you expect. What will happen when someone who expects the
old behavior tries to use it?

Mikael Høilund wrote:

Perhaps a bit controversial, but I’d like to see a keyword for the
�current block� as a way to refer to the Proc instance created inside
that block. That would allow for recursive anonymous blocks like:

[[1,2,[3]],[[[5],6],7],8].map { |e|
Array === e ? e.map(&current_block) : e.to_s
}

Appears maybe possible [Y combinator in Ruby]:
http://53cr.com/blog/2008/10/recursive-lambdas-in-ruby/
Cheers.
-=R