puts / print as method not keyword?

Z

zuzu

so, i'm thinking about language design with a particular interest in
concatinative combinators (postfix notation). you may remember my
questions and wonderful help jim weirich and others gave me some time
ago on the list w/r/t developing a pipes & filters syntax in ruby.

i started to worry that perhaps i was going to distort ruby out of
shape, when the case study i was running in my head seemed to be the
anomaly. most of my "this is weird" thoughts seem to stem from the
design of the Kernel object and subsequently how it is mixed in to the
Object object. (the Kernel object representing the ruby interpreter /
virtual machine itself; though the Object object representing the
rationally pure originator of all other objects supposedly including
the Kernel.)

so here's what i was thinking... quite alot of ruby idioms make use
of object methods to express themselves in a "data.manipulate" or
"data.express" format; that is, something like:

3.times

in a chain of

3.times {puts "thingy!"}

(perhaps others can contribute other examples, or just look them up
in the pickaxe -- thanks dave & andy.) but the Kernel's puts/print
fuction doesn't seem to carry over. it works fine as a global
keyword, but a programmer cannot

"this is a string".puts

and produce the desired result. instead the programmer must

puts "this is a string"

switching from postfix to prefix notation, most likely intuitive
because of experience C-style printf() or C++ style cout (or i suppose
BASIC).



however, i suppose the real answer should be "shut up and code it that
way for yourself then". but i want to throw this out there for
discussion as to why this was implemented in this way to begin with,
as well as gather information from those who know offhand where the
source of this lies in the default object library.

thanks,
-z
 
I

Ilmari Heikkinen

but the Kernel's puts/print
fuction doesn't seem to carry over. it works fine as a global
keyword, but a programmer cannot

"this is a string".puts

and produce the desired result. instead the programmer must

puts "this is a string"

As far as I know, it's a matter of

STDOUT.puts(string)

versus

string.puts(STDOUT)

(and then there's Kernel#p, which is an anomaly)
 
Z

zuzu

As far as I know, it's a matter of

STDOUT.puts(string)

versus

string.puts(STDOUT)

yes, precisely! :D

see, my concern then is that the "to where?" question becomes much
more obvious in the second, and much more necessary as ruby grows
beyond just a virtual machine running inside a unix environment or as
ruby grows as a networked language. perhaps i don't just want the
default STDOUT but would like to specify tty3 versus tty9 or perhaps
window7 of some screen tty multiplexing session or how emacs manages
buffers, and so on...

oh, also, correct me if i'm wrong, but method/function argument
passing really should only be used for CONSTRAINTS _not_ DATA.

and so i also feel that

string.puts(STDOUT)

or i'm probably thinking more like

string.puts {STDOUT}

much more closely follows the so-called "Principle of Least Surprise".
(and then there's Kernel#p, which is an anomaly)

due to its debugging intention, no?

peace,
-z

p.s. thanks for replying so quickly.
 
C

Carlos

but a programmer cannot

"this is a string".puts

and produce the desired result. instead the programmer must

puts "this is a string"

switching from postfix to prefix notation, most likely intuitive
because of experience C-style printf() or C++ style cout (or i suppose
BASIC).



however, i suppose the real answer should be "shut up and code it that
way for yourself then". but i want to throw this out there for
discussion as to why this was implemented in this way to begin with,
as well as gather information from those who know offhand where the
source of this lies in the default object library.

You have Object#display. But nobody uses it...

$ ri -T display
--------------------------------------------------------- Object#display
obj.display(port=$>) => nil
------------------------------------------------------------------------
Prints _obj_ on the given port (default +$>+). Equivalent to:

def display(port=$>)
port.write self
end

For example:

1.display
"cat".display
[ 4, 5, 6 ].display
puts

_produces:_

1cat456
 
Z

zuzu

try: "this is a string\n".display

word!!! yes, thank you.

now, why is this? :D
is this simply a matter of existing english documentation to prefer
"puts" or "print" over "display"?
is it that most programmers for better or worse desend from a
C/C++/Java background?


peace,
-z
 
Z

zuzu

2004-12-11 21.13 CET] said:
but a programmer cannot

"this is a string".puts

and produce the desired result. instead the programmer must

puts "this is a string"

switching from postfix to prefix notation, most likely intuitive
because of experience C-style printf() or C++ style cout (or i suppose
BASIC).



however, i suppose the real answer should be "shut up and code it that
way for yourself then". but i want to throw this out there for
discussion as to why this was implemented in this way to begin with,
as well as gather information from those who know offhand where the
source of this lies in the default object library.

You have Object#display. But nobody uses it...

thank you as well, with an even more complete answer.
(maybe someday ri will work by default on osx/darwin.)

from a language design perspective, or perhaps this is a ruby idomatic
/ programmer organization behavior perspective, any clues as to why
nobody uses it?

is it just obscure? not well documented in english (or at all)? just
not the way most programmers think due to their path-dependency (i.e.
first language learned, and all that...)?

peace,
-z
$ ri -T display
--------------------------------------------------------- Object#display
obj.display(port=$>) => nil
------------------------------------------------------------------------
Prints _obj_ on the given port (default +$>+). Equivalent to:

def display(port=$>)
port.write self
end

For example:

1.display
"cat".display
[ 4, 5, 6 ].display
puts

_produces:_

1cat456
 
B

Brian Schröder

2004-12-11 21.13 CET] said:
but a programmer cannot

"this is a string".puts

and produce the desired result. instead the programmer must

puts "this is a string"

switching from postfix to prefix notation, most likely intuitive
because of experience C-style printf() or C++ style cout (or i suppose
BASIC).



however, i suppose the real answer should be "shut up and code it that
way for yourself then". but i want to throw this out there for
discussion as to why this was implemented in this way to begin with,
as well as gather information from those who know offhand where the
source of this lies in the default object library.

You have Object#display. But nobody uses it...

thank you as well, with an even more complete answer.
(maybe someday ri will work by default on osx/darwin.)

from a language design perspective, or perhaps this is a ruby idomatic
/ programmer organization behavior perspective, any clues as to why
nobody uses it?

is it just obscure? not well documented in english (or at all)? just
not the way most programmers think due to their path-dependency (i.e.
first language learned, and all that...)?

[snip]

I can only tell from my experience. I never run across this, because I never
searched for it. I wanted to output something, so I searched for print, found
put and was not surprised at all...

So maybe the first languages learned where all very suggestive to me. What made
me enthusiastic about ruby is, that I can simply express myself the way I
expected to express myself. When trying to do logical (prolog) or purely
functional (haskell) programming, I always thought "intriguing idea, but I
can't map my mind to it". In ruby I can mix functional and imperative
programming and hack away - but without me noticing it my mind got/gets
transformed. I think ruby made me a better programmer in lots of ways. Maybe
someday I will even no longer ask the Kernel to display an object, but ask the
object to display itself. Or maybe I won't, because I always thought the other
way round.

Well, this became quite some prosa, but maybe it helps someone or at least
someone can find herself reflected in it.

Regards,

Brian
 
Y

Yukihiro Matsumoto

In message "Re: puts / print as method not keyword?"

|and so i also feel that
|
| string.puts(STDOUT)
|
|or i'm probably thinking more like
|
| string.puts {STDOUT}
|
|much more closely follows the so-called "Principle of Least Surprise".

It is very interesting to see how POLS differ person to person.
That's one of the reasons I discourage use of the word POLS in any
proposal. ;-)

"puts" was taken from UNIX C output function, which takes an output
string as an argument, so that it is more natural (for me at least) to
take functional form. I would be astonished very much when puts takes
output destination as an argument.

"display" was inherited from Smalltalk.

|see, my concern then is that the "to where?" question becomes much
|more obvious in the second, and much more necessary as ruby grows
|beyond just a virtual machine running inside a unix environment or as
|ruby grows as a networked language. perhaps i don't just want the
|default STDOUT but would like to specify tty3 versus tty9 or perhaps
|window7 of some screen tty multiplexing session or how emacs manages
|buffers, and so on...
|
|oh, also, correct me if i'm wrong, but method/function argument
|passing really should only be used for CONSTRAINTS _not_ DATA.

I don't see any obvious reasons behind your opinion. Can you
elaborate?

matz.
 
I

Ilmari Heikkinen

la, 2004-12-11 kello 22:38, zuzu kirjoitti:
perhaps i don't just want the
default STDOUT but would like to specify tty3 versus tty9 or perhaps
window7 of some screen tty multiplexing session or how emacs manages
buffers, and so on...

You would then replace STDOUT with e.g. STDERR, or even
File.open("log","a"){|f| f.puts(string) }
oh, also, correct me if i'm wrong, but method/function argument
passing really should only be used for CONSTRAINTS _not_ DATA.
and so i also feel that

string.puts(STDOUT)

or i'm probably thinking more like

string.puts {STDOUT}

much more closely follows the so-called "Principle of Least Surprise".

string.puts(STDOUT) creates a coupling, the string must call a method of the
given object with itself as the argument. It must know that the object it's
passed responds to #puts. Also, string.puts(STDOUT) modifies its argument
(by printing a new line), which, to me at least, is a big no-no.

STDOUT.puts(string) modifies only STDOUT. It doesn't (shouldn't) magically add
an extra line to the string. And maybe it's better to have all objects respond
to just #to_s instead of #puts, #print and #write.

The postfix notation is tempting though, hmm..
If you look at unix pipes, they use a syntax like:

method | method | method , last method taking care of doing things

The difference to Ruby's method.method.method is that the shell pipes aren't
namespaced to the preceding object. Ie. With shell pipes it'd be quite doable
to except the following to work in every situation:

gets | reverse | puts , because they are in the global namespace. What you pass
through the pipe doesn't change the available methods.

In ruby

gets.reverse.puts
creates a dependency chain.

gets must return something that responds to reverse, and reverse must return
something that responds to puts. Which is bad. So maybe we should emulate
shell pipes in some other way?


def in; yield self; end

string.in{|s| STDOUT.puts(s)}


Works in dataflow-style, too:

string.in{|s| puts s; s}.reverse.in{|s| puts s}

Keeps concerns to the objects whom they may concern (String
doesn't have to know about what methods IO has, etc.), and doesn't do
black-box modifications to its arguments.


Comments?
 
Z

zuzu

In message "Re: puts / print as method not keyword?"

|and so i also feel that
|
| string.puts(STDOUT)
|
|or i'm probably thinking more like
|
| string.puts {STDOUT}
|
|much more closely follows the so-called "Principle of Least Surprise".

It is very interesting to see how POLS differ person to person.
That's one of the reasons I discourage use of the word POLS in any
proposal. ;-)

quite true. it's quite subjective.
"puts" was taken from UNIX C output function, which takes an output
string as an argument, so that it is more natural (for me at least) to
take functional form. I would be astonished very much when puts takes
output destination as an argument.

this makes sense. particularly due, as you say, to experience with unix c.
"display" was inherited from Smalltalk.

aaaah, very interesting.
|see, my concern then is that the "to where?" question becomes much


|more obvious in the second, and much more necessary as ruby grows
|beyond just a virtual machine running inside a unix environment or as
|ruby grows as a networked language. perhaps i don't just want the
|default STDOUT but would like to specify tty3 versus tty9 or perhaps
|window7 of some screen tty multiplexing session or how emacs manages
|buffers, and so on...
|
|oh, also, correct me if i'm wrong, but method/function argument
|passing really should only be used for CONSTRAINTS _not_ DATA.

I don't see any obvious reasons behind your opinion. Can you
elaborate?

matz.

for the function argument issue... i think the idea of constraints
has its origins in math just as the idea of a function does. however,
i encounter it much more vocally in the study of process in the fields
of systems theory and cybernetics. when utilizing a process model to
solve a problem, a differentiation is made between variables (the
unknowns you seek to know) and constraints (arbitrary filters to limit
the search space).
however, this does become not so obvious in the real world where the
data output from one function can define the constraints input into
another function. but in many dataflow languages, and i think even in
the useful difference between closures and function arguments, a
distinction is made between the dataflow and "defining the filters"
(constraints).

as for the issue of defining what STDOUT is set to... this seems
"obvious" to me because of the dataflow involved, moving a stream
linearly from inputs to outputs. usually a screen or printer to
teletype or such is the "final" output / destination, or at least
represents the intersection where that stream of information is then
input into a human and an "input device" such as a keyboard or mouse
receives human output back into the computer -- so thus a cycle of
human-computer interaction persists with the human as just another
filter/generator.

i hope i explained this well. i will be happy to elaborate futher.
-z
 
C

Carlos

thank you as well, with an even more complete answer.
(maybe someday ri will work by default on osx/darwin.)

from a language design perspective, or perhaps this is a ruby idomatic
/ programmer organization behavior perspective, any clues as to why
nobody uses it?

is it just obscure? not well documented in english (or at all)? just
not the way most programmers think due to their path-dependency (i.e.
first language learned, and all that...)?

I can rationalize it: print is more convenient because it allows more than
one argument. Also, why an object should know anything about ports? The
object should know how to stringify itself and the port should know about
printing strings and that's all.

But probably the real reason is that I learnt print and puts first. #display
looks awkward to me. Maybe I would think different if I learned #display
first.

It would be an interesting experiment to try to program using only #display.
 
Z

zuzu

la, 2004-12-11 kello 22:38, zuzu kirjoitti:


You would then replace STDOUT with e.g. STDERR, or even
File.open("log","a"){|f| f.puts(string) }

i wouldn't want to save to a file as an intermediary, and then have to
use something like the 'tail' command in another tty... (for example,
imagine if you were writing a cryptography tool). but since in unix
"everything is a file", i suppose some way could exist to write to a
tty "file" directly.

though what i am really imagining is something such as a window
manager written in ruby, where the display windows are objects
(instances of a Window class or whatever), and take advantage of
"everything is an object" rather than "everything is a file". like
naked object or the self language, i would like then for window
objects to say how to display themselves to the screen object.
string.puts(STDOUT) creates a coupling, the string must call a method of the
given object with itself as the argument. It must know that the object it's
passed responds to #puts.

i think to me this seems natural for the pure-OO "everything is an
object" nature of ruby (or smalltalk). strings know how to display
themselves, they just need to know where. again, i think "naked
objects" is the latest way to talk about this, though i often think of
self language which was built on smalltalk.
Also, string.puts(STDOUT) modifies its argument
(by printing a new line), which, to me at least, is a big no-no.

i agree that the appending of a newline feels like a no-no.
STDOUT.puts(string) modifies only STDOUT. It doesn't (shouldn't) magically add
an extra line to the string. And maybe it's better to have all objects respond
to just #to_s instead of #puts, #print and #write.

The postfix notation is tempting though, hmm..
If you look at unix pipes, they use a syntax like:

method | method | method , last method taking care of doing things

yes! yes! yes! again, referring to those old emails i had here on
the list with jim weirich, the streams/dataflow/coroutines approach of
pipes and filters (commonly experienced in unix) was my inspiration.
but this chaining is not at all foreign to ruby, as quite often data
"collects and selects" are performed with method chaining. e.g.

Object.methods.sort
The difference to Ruby's method.method.method is that the shell pipes aren't
namespaced to the preceding object. Ie. With shell pipes it'd be quite doable
to except the following to work in every situation:

gets | reverse | puts , because they are in the global namespace. What you pass
through the pipe doesn't change the available methods.

In ruby

gets.reverse.puts
creates a dependency chain.

gets must return something that responds to reverse, and reverse must return
something that responds to puts. Which is bad.

hmmm... is this any different than unix which works blindly in bytestreams?
So maybe we should emulate
shell pipes in some other way?

def in; yield self; end

string.in{|s| STDOUT.puts(s)}

Works in dataflow-style, too:

string.in{|s| puts s; s}.reverse.in{|s| puts s}

Keeps concerns to the objects whom they may concern (String
doesn't have to know about what methods IO has, etc.), and doesn't do
black-box modifications to its arguments.

Comments?

hehe, now i have to dig up those old emails for myself and really put
my brain to work on this.

thanks!!!
-z
 
Z

zuzu

here is how jim was thinking of it. he seems to love mixing in
Enumerable for all kinds of fun dataflow tricks, and that seemed not
such a bad idea to me.

but don't let this stifle your creativity thinking about postfix /
concatenative combinators this time around. (the terminology of
"concatenative combinators" first found me by way of the Forth
language, which then influenced the Toy language. feel free to also
browse jim cunningham's excellent programming language wiki at
c2.com).

From: Jim Weirich <[email protected]>
Reply-To: (e-mail address removed)
To: ruby-talk ML <[email protected]>
Date: Fri, 27 Aug 2004 11:07:09 +0900
Subject: Re: python generators to ruby closures, help

William said:
Yes. I don't think you want the Generator class at all then. As the
email you quoted said, Python generators are a solution to a problem
that Ruby doesn't have. Generators have a place in Ruby but this ain't
it.

From what I can tell, all the functionality they build up in the Python
example is just so that they can do thing that in Ruby can be done
neatly with iterators, like this:

As William pointed out, enumerator pipes can be implemented in Ruby
without resorting to continuations, and that the current enumerator
syntax is very pipe-like in many ways.

However, one thing the Python version handles that enumerator chaining
does not is an infinite enumerator. In the python examples, we have
the following construct:

Ints() | firstTen | oddNotDivBy3

Ints() is a generator that will generate all the integers (given
enough time and space). The next filter "firstTen" only takes the
first 10 of those numbers. Since the generator chain only takes a
number from a generator when it is needed, the Ints() generator is
never asked for any more than 10 number.

We can do the same with Ruby enumerators. Imagine a OddNumberFilter
object that implements a each method like this ...

class OddNumberFilter
include Enumerable
attr_accessor :source
def each
@source.each { |n| yield(n) if (n % 2) != 0 }
end
end

It uses a source enumerable to generate numbers and only yields when
it finds an odd number. We can use it like this ...

odds_only = OddNumberFilter.new
odds_only.source = (1..10)
odds_only.to_a # => [1, 3, 5, 7, 9]

Since a filter can take _any_ enumerable as a source, it can even take
other filters. Let's generalize our OddNumberFilter class to a
CondFilter class that takes a condition and only passes items that
pass the condition.

class CondFilter
include Enumerable
attr_accessor :source
def initialize(&block)
@block = block
end
def each
@source.each { |it| yield(it) if @block.call(it) }
end
end

Now we create a chain of filters ...

odds_only = CondFilter.new { |n| (n % 2) != 0 }
odds_only.source = (1..10)

divisible_by_three = CondFilter.new { |n| (n % 3) == 0 }
divisible_by_three.source = odds_only

divisible_by_three.to_a #=> [3, 9]

It works, but it is ugly. So lets create a little syntactic sugar to
get this to work ...

module Enumerable
def |(filter)
filter.source = self
filter
end
end

odds_only = CondFilter.new { |n| (n%2) != 0 }
divisible_by_three = CondFilter.new { |n| (n%3) == 0 }

pipe = (1..10) | odds_only | divisible_by_three
pipe.to_a # => [3, 9]

With this foundation, handling infinite enumerations are easy ...

class Ints
include Enumerable
def initialize
@n = 0
end
def each
loop do
yield @n
@n += 1
end
end
end

And a class to take only so many items ...

class Take
include Enumerable
attr_accessor :source

def initialize(limit)
@limit = limit
end
def each
n = 0
@source.each do |it|
n += 1
break if n > @limit
yield it
end
end
end

( Ints.new | Take.new(5) ).to_a # => [0, 1, 2, 3, 4]

From this point the File generator and the other stuff in the Python
example should be obvious.

Here's a fun puzzle. Using filters, create a Sieve of Erasothanes
filter that, given an input of Ints.new, will generate a series of
prime numbers. In other words, the code ...

( Ints.new | Primes.new | Take.new(100) ).to_a

will create an array of the first 100 prime numbers.

I've attached full examples and test suites for all the the above
(although factored a bit differently), so don't peek if you want to work
out the Primes puzzle ...

--
-- Jim Weirich (e-mail address removed) http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

#!/usr/bin/env ruby

require 'find'

module Enumerable
def |(filter)
filter.source = self
filter
end
end

class EmptyEnumClass
include Enumerable
def each() end
end

EmptyEnum = EmptyEnumClass.new

class EnumFilter
include Enumerable
attr_reader :source
def initialize(source=nil)
@source = source || EmptyEnum
end
def source=(new_source)
case @source
when EnumFilter
@source.source = new_source
else
@source = new_source
end
end
def each(&block)
@source.each(block)
end
end

class CondFilter < EnumFilter
def initialize(&block)
super()
@block = block
end
def each
@source.each do |it| yield it if @block[it] end
end
end

class Ints
include Enumerable
def initialize
@n = 0
end
def each
loop do
yield @n
@n += 1
end
end
end

class Quit < EnumFilter
def initialize(&block)
@block = block
end
def each
@source.each do |it|
break if @block[it]
yield it
end
end
end

class Start < EnumFilter
def initialize(start)
@start = start
end
def each
@source.each do |it|
yield it if it >= @start
end
end
end

class Take < EnumFilter
def initialize(limit)
@limit = limit
end
def each
n = 0
@source.each do |it|
break if n >= @limit
yield it
n += 1
end
end
end

class EnumFiles
include Enumerable
def initialize(fn)
@file_name = fn
end
def each
Find.find(@file_name) do |fn| yield fn end
end
end

class Primes < EnumFilter
def initialize
super
@source = Start.new(2)
end
def each
loop do
n = (@source | Take.new(1)).to_a[0]
yield n
@source = @source | new_filter(n)
end
end
def new_filter(n)
CondFilter.new { |it| (it%n) != 0 }
end
end

#!/usr/bin/env ruby

require 'test/unit'
require 'enumpipe'

class TestEnumPipe < Test::Unit::TestCase

def test_create
ep = CondFilter.new
assert ep
end

def test_odd
odd_filter = CondFilter.new { |it| (it % 2) != 0 }
odd_filter.source = (1..10)
assert_equal [1,3,5,7,9], odd_filter.to_a
end

def test_no_source
odd_filter = CondFilter.new { |it| (it % 2) != 0 }
assert_equal [], odd_filter.to_a
end

def test_two_filters
odd_filter = CondFilter.new { |it| (it % 2) != 0 }
filter_thirds = CondFilter.new { |it| (it % 3) == 0 }
odd_filter.source = (1..10)
filter_thirds.source = odd_filter
assert_equal [3, 9], filter_thirds.to_a
end

def test_left_pipeing
odd_filter = CondFilter.new { |it| (it % 2) != 0 }
filter_thirds = CondFilter.new { |it| (it % 3) == 0 }
filter_thirds.source = odd_filter
filter_thirds.source = (1..10)
assert_equal [3, 9], filter_thirds.to_a
end

def test_pipe_syntax
pipe = (1..10) | CondFilter.new { |it| (it%2) != 0 }
assert_equal [1,3,5,7,9], pipe.to_a
end

def test_pipe_three
src = (1..10)
odd = CondFilter.new { |it| (it%2) != 0 }
thirds = CondFilter.new { |it| (it%3) == 0 }
pipe = src | odd | thirds
assert_equal [3, 9], pipe.to_a
end

def test_pipe_right_associative
src = (1..10)
odd = CondFilter.new { |it| (it%2) != 0 }
thirds = CondFilter.new { |it| (it%3) == 0 }
pipe = src | (odd | thirds)
assert_equal [3, 9], pipe.to_a
end

def test_infinite_takes
pipe = Ints.new | Take.new(10)
assert_equal (0...10).to_a, pipe.to_a
end

def test_multiple_takes_on_ints
pipe = Ints.new | Take.new(2)
assert_equal [0,1], pipe.to_a
assert_equal [2,3], pipe.to_a
assert_equal [4,5], pipe.to_a
end

def test_quit_filter
pipe = Ints.new | Quit.new { |it| it > 5 }
assert_equal [0,1,2,3,4,5], pipe.to_a
end

def test_start
pipe = Ints.new | Start.new(5) | Take.new(3)
assert_equal [5,6,7], pipe.to_a
end

def test_files
files = EnumFiles.new(".")
filelist = files.to_a
assert filelist.member?("./enumpipe.rb")
assert filelist.member?("./testenumpipe.rb")
end

def test_file_filter
testfiles = EnumFiles.new('.') | CondFilter.new { |fn|
File.basename(fn) =~ /^test.*\.rb$/ }
filelist = testfiles.to_a
assert filelist.member?("./testenumpipe.rb")
end

def test_primes
primes = Ints.new | Primes.new | Take.new(10)
assert_equal [2,3,5,7,11,13,17,19,23,29], primes.to_a
end

end
 
Z

zuzu

here is how jim was thinking of it. he seems to love mixing in
Enumerable for all kinds of fun dataflow tricks, and that seemed not
such a bad idea to me.

but don't let this stifle your creativity thinking about postfix /
concatenative combinators this time around. (the terminology of
"concatenative combinators" first found me by way of the Forth
language, which then influenced the Toy language. feel free to also
browse jim cunningham's excellent programming language wiki at
c2.com).

er, ward cunningham. got jim on the brain. :p sorry ward.
From: Jim Weirich <[email protected]>
Reply-To: (e-mail address removed)
To: ruby-talk ML <[email protected]>
Date: Fri, 27 Aug 2004 11:07:09 +0900
Subject: Re: python generators to ruby closures, help

William said:
Yes. I don't think you want the Generator class at all then. As the
email you quoted said, Python generators are a solution to a problem
that Ruby doesn't have. Generators have a place in Ruby but this ain't
it.

From what I can tell, all the functionality they build up in the Python
example is just so that they can do thing that in Ruby can be done
neatly with iterators, like this:

As William pointed out, enumerator pipes can be implemented in Ruby
without resorting to continuations, and that the current enumerator
syntax is very pipe-like in many ways.

However, one thing the Python version handles that enumerator chaining
does not is an infinite enumerator. In the python examples, we have
the following construct:

Ints() | firstTen | oddNotDivBy3

Ints() is a generator that will generate all the integers (given
enough time and space). The next filter "firstTen" only takes the
first 10 of those numbers. Since the generator chain only takes a
number from a generator when it is needed, the Ints() generator is
never asked for any more than 10 number.

We can do the same with Ruby enumerators. Imagine a OddNumberFilter
object that implements a each method like this ...

class OddNumberFilter
include Enumerable
attr_accessor :source
def each
@source.each { |n| yield(n) if (n % 2) != 0 }
end
end

It uses a source enumerable to generate numbers and only yields when
it finds an odd number. We can use it like this ...

odds_only = OddNumberFilter.new
odds_only.source = (1..10)
odds_only.to_a # => [1, 3, 5, 7, 9]

Since a filter can take _any_ enumerable as a source, it can even take
other filters. Let's generalize our OddNumberFilter class to a
CondFilter class that takes a condition and only passes items that
pass the condition.

class CondFilter
include Enumerable
attr_accessor :source
def initialize(&block)
@block = block
end
def each
@source.each { |it| yield(it) if @block.call(it) }
end
end

Now we create a chain of filters ...

odds_only = CondFilter.new { |n| (n % 2) != 0 }
odds_only.source = (1..10)

divisible_by_three = CondFilter.new { |n| (n % 3) == 0 }
divisible_by_three.source = odds_only

divisible_by_three.to_a #=> [3, 9]

It works, but it is ugly. So lets create a little syntactic sugar to
get this to work ...

module Enumerable
def |(filter)
filter.source = self
filter
end
end

odds_only = CondFilter.new { |n| (n%2) != 0 }
divisible_by_three = CondFilter.new { |n| (n%3) == 0 }

pipe = (1..10) | odds_only | divisible_by_three
pipe.to_a # => [3, 9]

With this foundation, handling infinite enumerations are easy ...

class Ints
include Enumerable
def initialize
@n = 0
end
def each
loop do
yield @n
@n += 1
end
end
end

And a class to take only so many items ...

class Take
include Enumerable
attr_accessor :source

def initialize(limit)
@limit = limit
end
def each
n = 0
@source.each do |it|
n += 1
break if n > @limit
yield it
end
end
end

( Ints.new | Take.new(5) ).to_a # => [0, 1, 2, 3, 4]

From this point the File generator and the other stuff in the Python
example should be obvious.

Here's a fun puzzle. Using filters, create a Sieve of Erasothanes
filter that, given an input of Ints.new, will generate a series of
prime numbers. In other words, the code ...

( Ints.new | Primes.new | Take.new(100) ).to_a

will create an array of the first 100 prime numbers.

I've attached full examples and test suites for all the the above
(although factored a bit differently), so don't peek if you want to work
out the Primes puzzle ...
 
I

Ilmari Heikkinen

i think to me this seems natural for the pure-OO "everything is an
object" nature of ruby (or smalltalk). strings know how to display
themselves, they just need to know where. again, i think "naked
objects" is the latest way to talk about this, though i often think of
self language which was built on smalltalk.

Regarding the "string displaying itself"-bit, my view is that a string
can suggest how it should be displayed, but the final call is in the
hands of the display object.
As dataflow: cat string | /dev/display

hmmm... is this any different than unix which works blindly in
bytestreams?

The shell pipes differ in that shell commands are all "instance methods
of class Bytestream", but in Ruby the input object and output object
may be of different classes. So there's a possibility of interface
mismatch.

With shell commands, the methods all have the same input and output
type, but they are liable to fail if the incoming stuff doesn't quite
agree with what the command was built to handle.

cat my.wav | lame - - | madplay -
cat my.txt | lame - - | madplay -
# if my.txt happens to be a valid wav file, it works
# if not, lame blows up.

Compared to:
Wav.new('my.wav').lame.madplay # works, may fail inside call to lame
if input is bad
Txt.new('my.txt').lame.madplay #=> NoMethodError, even if my.txt is
a valid wav file


The way shell commands work could be rubyized as:

require 'thread'

class ShellPipe
# create method for each command in each path with
# paths in front overriding later ones
# quite obtuse.
ENV['PATH'].split(/:/).reverse.each{|path_root|
Dir[File.join(path_root, "*")].each{|bin_name|
define_method(File.split(bin_name).last){|*args|
full_cmd = [bin_name, *args].join(" ")
self.class.new(
self,
IO.popen(full_cmd, 'r+')
)
}
}
}

def initialize(input, filter, stopped=false)
@input = input
@filter = filter
@stopped = stopped
@mutex = Mutex.new
@cond = ConditionVariable.new
suck_on_input
end

def silently_fail
yield
rescue
end

def method_missing(m, *args, &block)
@filter.send(m, *args, &block)
rescue NoMethodError
super
end

def suck_on_input
silently_fail{ @input_sucker.kill }
@input_sucker = Thread.new{
begin
@mutex.synchronize{
until @input.eof?
@cond.wait(@mutex) if @stopped
@filter.write @input.read(4096)
end
}
ensure
@filter.close_write
end
}
end

def start
return nil unless @stopped
@mutex.synchronize{
@stopped = false
@cond.signal
}
end

def stop
@stopped = true
end

def read(*args)
@filter.read(*args)
end

def close
@input.close if @input and not @input.closed?
ensure
@filter.close
end
end

my_wav = ShellPipe.new(nil, File.open("my.wav"))
player = my_wav.lame("-", "-").madplay("-")
player.read
player.close # cascades up the pipe



Got a little carried away there, sorry about that :)
 
Z

zuzu

Regarding the "string displaying itself"-bit, my view is that a string
can suggest how it should be displayed, but the final call is in the
hands of the display object.
As dataflow: cat string | /dev/display

yes yes, i agree. i came to the same conclusion some time ago
discussing the ION windowmanager with tuomo valkonen.
http://modeemi.cs.tut.fi/~tuomov/ion/#intro (windowmanagers
conforming to the ICCCM, not applications themselves, should decide
how they are drawn. but the applications convey to the windowmanager
*what* needs to be drawn.)
the naked objects book is online at
http://www.nakedobjects.org/book/content.html (though i personally
favor a GUI much more like ION / screen / emacs than the popular WIMP
design.)
The shell pipes differ in that shell commands are all "instance methods
of class Bytestream", but in Ruby the input object and output object
may be of different classes. So there's a possibility of interface
mismatch.

ah, yes. hence the .to_x adapter methods (popularly, .to_s). this
may be the ruby way, but something is scratching at the back of my
subconscious that i've seen something regarding language design about
how this can possibly be inferred by the interpreter or that there's
an elegant design way around it... if/when i think of this hopefully
i'll remember to post... (something related to duck-typing maybe???)
With shell commands, the methods all have the same input and output
type, but they are liable to fail if the incoming stuff doesn't quite
agree with what the command was built to handle.

cat my.wav | lame - - | madplay -
cat my.txt | lame - - | madplay -
# if my.txt happens to be a valid wav file, it works
# if not, lame blows up.

right, this was what i was trying to allude to before w/r/t
bytestreams. though again, if there's an elegant way for the code to
know when something won't connect properly, that's better for the
programmer / user i think.
Compared to:
Wav.new('my.wav').lame.madplay # works, may fail inside call to lame
if input is bad
Txt.new('my.txt').lame.madplay #=> NoMethodError, even if my.txt is
a valid wav file

right right, useful feedback is very important. i'm all about
introspection/reflection; i <3 irb.
The way shell commands work could be rubyized as:

require 'thread'

i need to look over this code in more detail, but as an aside i would
like to avoid ruby-threads (and threads in general) as a matter of the
problems with shared-state-concurrency. a longer-term goal i am
seeking is to extend ruby from pure-OO to pure-actors (as in carl
hewitt's actors model, 'concepts techniques and models of computer
programming' elaborates on this where the SICP does not).
essentially, every object instance would be its own actor, though this
may require writing an alternate VM for ruby which would utilize what
(e-mail address removed) refers to as "no kernel" architecture (
http://cliki.tunes.org/No-Kernel ); though compatability would be
maintained by aliasing any Kernel object requests back to the Object
object (sort of the inverse of the current mix-in implementation).

jim's method conveniently side-steps the issue on the ruby-code side
of things by using Enumerable instead. though this may not be the
"perfect" solution either. i hope to spend more time starting this
week to try some experimentation with these models in actual code.


i think somewhere someone also mentioned that in common programming
there is often a muddeling between design and platform implementation,
or something regarding optimization.... (i don't think it was the
TAoUP... was it?) but the gist was that the language should aid
design, and the interpreter (VM, compiler, whatever...) should already
know and automate the optimal solutions to problems like "should this
be threaded?" a common example today, though oddly still hotly
debated, is manual memory management versus garbage collection (GC).
according to this "sage advice" i am trying to recall here, language
should not offer manual memory management (i hear all the
C/asm/"efficiency" nazis crawling out of the woodwork as i type
this...) because it is precisely the kind of task which the computer
will *consistently* do better than a human. yes, once in a blue moon
a human can exert an excessive effort to outsmart a GC, but doing so
and not creating buggy code requires a super-human programmer to both
create _and maintain_; to quote from the TAoUP however, "computer time
is cheap. human time is expensive."

my point is, any ruby code that actually sticks around to implement
something like late-binding / lazy-evaluation streams / dataflow
should rely on the transparency of the interpreter / VM to decide the
optimal utilization of the underlying hardware, and hopefully, as john
backus desired, free us from the constraints of the von neumann
machine. (however, ilmari, i realize your code was merely some
brainstorming. popular brainstorming of designs in code is the
pursued ideal here afterall.)

peace,
-z
class ShellPipe
# create method for each command in each path with
# paths in front overriding later ones
# quite obtuse.
ENV['PATH'].split(/:/).reverse.each{|path_root|
Dir[File.join(path_root, "*")].each{|bin_name|
define_method(File.split(bin_name).last){|*args|
full_cmd = [bin_name, *args].join(" ")
self.class.new(
self,
IO.popen(full_cmd, 'r+')
)
}
}
}

def initialize(input, filter, stopped=false)
@input = input
@filter = filter
@stopped = stopped
@mutex = Mutex.new
@cond = ConditionVariable.new
suck_on_input
end

def silently_fail
yield
rescue
end

def method_missing(m, *args, &block)
@filter.send(m, *args, &block)
rescue NoMethodError
super
end

def suck_on_input
silently_fail{ @input_sucker.kill }
@input_sucker = Thread.new{
begin
@mutex.synchronize{
until @input.eof?
@cond.wait(@mutex) if @stopped
@filter.write @input.read(4096)
end
}
ensure
@filter.close_write
end
}
end

def start
return nil unless @stopped
@mutex.synchronize{
@stopped = false
@cond.signal
}
end

def stop
@stopped = true
end

def read(*args)
@filter.read(*args)
end

def close
@input.close if @input and not @input.closed?
ensure
@filter.close
end
end

my_wav = ShellPipe.new(nil, File.open("my.wav"))
player = my_wav.lame("-", "-").madplay("-")
player.read
player.close # cascades up the pipe

Got a little carried away there, sorry about that :)
 
I

Ilmari Heikkinen

Sorry in advance for going to come across as a raving lunatic :|
(windowmanagers
conforming to the ICCCM, not applications themselves, should decide
how they are drawn. but the applications convey to the windowmanager
*what* needs to be drawn.)

Kind of like X(HT)ML + Cascading Style Sheets. You get the abstract UI
object
from the network, pipe it through an abstract UI -> specific UI
-converter, which looks through the UI's style metadata, does some hard
decisions based on user preferences and system configuration, and
creates a UI object conforming to the GUI toolkit of the day.

though again, if there's an elegant way for the code to
know when something won't connect properly, that's better for the
programmer / user i think.

Yes. If we have the types for a pipe's input and output and a bunch of
info about how the pipe command works, it's perfectly feasible to build
an RDF ontology for describing a pipe command, and then describe each
command using that ontology, thus creating a conversion graph, and then
using that to build programs based on wanted input and output types.

The hard part is making a weighing function for the graph edges to get
semantically correct results. And a type detection function to deduct a
type for a file. The concrete file format is quite easy with the
extension metadata and magic glob matching (using e.g.
freedesktop.org's shared-mime-info database), but semantic type is a
good deal more work.
In the beginning it would likely be human-generated metadata, mostly,
but it is quite likely that some combination of bayesian classification
and old-fashioned heuristics would yield good enough accuracy for
classifying (text) documents, as seen with spam filters. And I suppose
there's a wealth of data that can be scraped off all the little nooks
and crannies of many files (EXIF data, ID3 tags, creation data, place
in directory structure, files that are often open at the same time,
usual location on the screen, network traffic patterns...)
i need to look over this code in more detail, but as an aside i would
like to avoid ruby-threads (and threads in general) as a matter of the
problems with shared-state-concurrency.

Agreed, state is a pain. As are loops. And flow control in general.
a longer-term goal i am
seeking is to extend ruby from pure-OO to pure-actors (as in carl
hewitt's actors model, 'concepts techniques and models of computer
programming' elaborates on this where the SICP does not).

The actor language paradigm is very interesting. Especially the parts
about doing things with async message passing, assigning successors and
passing computations around.

I'm writing a sort of domain language with actor influences it seems.
Centered around events, search, list processing and automatic data
conversions. Probably using Gnome Beagle for search and Ruby + friends
for rest.

e = Eventhandler.new("Email")
def e.new(headers, body)
if People["work"].matches? headers.sender
Devices[Audio].play body
end
end
MessageDaemon.Email.new(some_header, some_body)

Data conversion and events are somewhat done, Enumerable is good for
list processing, no search yet. Who knows if that ever gets off the
ground.

and the interpreter (VM, compiler, whatever...) should already
know and automate the optimal solutions to problems like "should this
be threaded?"

And whether it should run it on the local computer or send it to
somewhere else on the local cluster or even use remote services to
achieve the goal.

Ideal programming language: think out loud "I wish I had some pizza
here.." and the interpreter weighs the strength of your wish against
the negative effects that getting a pizza would incur (cost in money,
health effects, delivery time, psychological effects), and also takes
into account outcomes of possible historical incidents regarding
surprise pizza.
And then you'd just get a pizza. Or not.

to quote from the TAoUP however, "computer time
is cheap. human time is expensive."

Hence you must tax both the computer and human component to the
extremes to get to the global time usage minimum. Tax in a way that is
most natural and effective for both. Human prowling the savannah of
info looking for edible fruits, predators, prey and other humans,
computer living in a world of high-speed serial computation. Computer
communicating to human with 50MBps audio-video feed of as much data
visible at once as the computer can display (show it all, let the
visual center sort it out), human communicating to computer by talking,
pointing, drawing and gesturing.
my point is, any ruby code that actually sticks around to implement
something like late-binding / lazy-evaluation streams / dataflow
should rely on the transparency of the interpreter / VM to decide the
optimal utilization of the underlying hardware

Yea. Anything to let me do more things in the same time. :)
 
G

Gavin Sinclair

i think to me this seems natural for the pure-OO "everything is an
object" nature of ruby (or smalltalk). strings know how to display
themselves, they just need to know where. again, i think "naked
objects" is the latest way to talk about this, though i often think of
self language which was built on smalltalk.

I'm not normally given to this kind of negative exuberance, but ...

... that is just ABSURD!!!

Do you seriously think a string should know how to output itself to
the console, a graphics canvas, a printer, a fax machine, a network
connection, a sky-writing aeroplane, and every other bloody output
device!!?!?!?

In Ruby, everything is already an object. The output devices
included. Let's leave the details of rendering output to them and
them alone, shall we?

Claiming that #puts is polluting the OO nature of Ruby (perhaps noone
has done this, but they compare it to legacy procedural languages) is
sheer bloody madness. What do I love about Ruby?

def output_something(out=STDOUT)
...
out.puts "something"
...
end

output_something(STDERR)
output_something(StringIO.new)
output_something(Socket.open)
output_something(File.open)
output_something(FaxMachine.discover)
output_something(SkyWriter.yeah_right)

Having a pure OO language delivers us great practical benefit. Let's
keep it that way, and keep enjoying _practical_ benefits rather than,
in the name of purity, turn all our objects into politicians who
endlessly defer responsibility for actually doing anything.

Sorry for any harshness. This kind of discussion just drives me round
the bend. And that's not fair, because it's the people with the crazy
ideas that bring progress. ("Whaddaya mean, you can add methods to
existing classes, you nutjob?")

Cheers,
Gavin
 
Z

zuzu

I'm not normally given to this kind of negative exuberance, but ...

... that is just ABSURD!!!

Do you seriously think a string should know how to output itself to
the console, a graphics canvas, a printer, a fax machine, a network
connection, a sky-writing aeroplane, and every other bloody output
device!!?!?!?

read my clarification. it should know how to describe itself /
present itself to output objects, be they a console, a graphics
canvas, a printer, et. al. this would be the difference between
postscript and the displaypostscript engine.

also, as i think ilmari mentioned, perhaps this is really an issue
more along the lines of .to_s, to be sent to some kind of display
object rather than #puts in the Kernel (which assumes STDOUT).
In Ruby, everything is already an object. The output devices
included. Let's leave the details of rendering output to them and
them alone, shall we?

well, yes. i'm not disputing this. i'm balley-hoo for "everything is
an object". but, i have a feeling (perhaps irrational) that
Kernel#puts is a kludge of the VM. (actually, iirc it is just an
alias to something C++ like with STDOUT << "some string".)

my original point was to favor a postfix (concatenative combinator)
notation for directing outputs at the outset, rather than a prefix
notation of keywords that smells like imperative/procedural
programming. #display offers a postfix notation for now.
Claiming that #puts is polluting the OO nature of Ruby (perhaps noone
has done this, but they compare it to legacy procedural languages) is
sheer bloody madness.

i wouldn't say polluting... the thing about OO is that it's
completely orthogonal to the imperative/procedural vs. functional
debate. ruby very elegantly side-steps this issue with blocks (as
functions), and a list of procedures is a list -- written vertically
instead of horizontally. (though once things start getting into
accessors and attributors, side-effects get prickly again, i think.)

but what i love about ruby is how most idioms seem to favor the
object-functional route, especially that closures are favored over
loops for iteration (though ruby does support loops such as 'while').
What do I love about Ruby?

def output_something(out=STDOUT)
...
out.puts "something"
...
end

output_something(STDERR)
output_something(StringIO.new)
output_something(Socket.open)
output_something(File.open)
output_something(FaxMachine.discover)
output_something(SkyWriter.yeah_right)

ok, i'm all for choosing outputs. but the issue i brought forward is
that the work in this kind of example i think is rare, or at least is
counter to how i want to think about most of my problems. for me, the
data of "something" is almost never static. i need to parse emails,
html, system logs, irc logs, on and on and on... the "something" is
an infinite stream and never hard-coded by me. where i output it to,
however, is a constraint, and not only finite but probably fewer than
i can count on my fingers.

however, again as ilmari has clarified, the issue of namespace arises.
we cannot

object.method.method.method.method

without making object some kind of uber-object which defeats the
purpose of namespace and thus objectification in the firstplace. i
*think* this is where you feel flummoxed. what i would like to see is
syntactic sugar for pipelining dataflow across multiple objects which
are compartmentalized rationally (and, eventually, separate processes
as well for sake of concurrency).

fuel.method.method | oxygen.method | sparkplug.method.method

then the really cute part about lazy-evaluation is this can be shifted
across time...

fuel.method.method | oxygen.method

(several hours pass)

oxygen.method | sparkplug.method.method

which, again referencing backus as well as what most functional
programmers tend to have a hard-on about with regards to things like
referential transparency is that we can forget, as designers, about
time. it doesn't matter *when* things get done, as long as they
eventually do; and we don't even have to specify the correct order for
how things get done, as long as all the pieces are there. eventually,
this approaches declarative programming, but not in the oft thought of
logic programming sense. it just means we tell the computer what to
do, not how to do it. this leads towards code that looks alot more
like issuing command-lines (as end-users still often do in operating
systems).
Having a pure OO language delivers us great practical benefit. Let's
keep it that way, and keep enjoying _practical_ benefits rather than,
in the name of purity, turn all our objects into politicians who
endlessly defer responsibility for actually doing anything.

endlessly defer.... well, according to message-passing architecture
(smalltalk, ruby, actors), i believe this means that messages are
passed in the reverse flow of the dataflow. data flows downstream
while requests for data flow upstream. data is processed lazily -- it
gets done when it's available; as opposed to eager-evaluation where
team B can only start once team A is completely finished. frankly, i
much rather see web sites load as the html is parsing rather than
waiting what feels like endless seconds/minutes for the entire dom to
validate.
Sorry for any harshness. This kind of discussion just drives me round
the bend. And that's not fair, because it's the people with the crazy
ideas that bring progress. ("Whaddaya mean, you can add methods to
existing classes, you nutjob?")

hehe, as long as we're all willing to leave ego behind (no ad hominem
attacks) i'm willing to argue the validity of the issues as much as
necessary (or as my time permits). hopefully ruby itself won't have
its feelings hurt.
Cheers,
Gavin

peace,
-z
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top