Wow, you're meddling in some pretty interesting things here. I don't think Ruby is that fit for them, however. Forth is a language without arguments. You just have a stack shared by all. It's elegant as hell and I love it, and it's first on my list of things to meddle with seriously. Forth code looks like this: : fib-iter ( n -- f ) ( things in braces are comments ) 0 1 rot 0 ?do over + swap loop drop ; Here's an explanation: http://en.literateprograms.org/Fibonacci_numbers_(Forth)#chunk%20def:fib-iter Ask Ed Borasky. He's very enthusiastic about it. Your later ideas sound to me a bit like Haskell monads, of which I've read a very good explanation recently that I've forgot the link for (there's a whole industry of trying to explain what monads are). Aur On 6/17/07, Trans <transfire / gmail.com> wrote: > > > On Jun 16, 3:52 am, "Erwin Abbott" <erwin.abb... / gmail.com> wrote: > > On 6/16/07, Trans <transf... / gmail.com> wrote: > > > > > > > > > Thanks Erwin, that helps. I was toying with not having any methd > > > arguments. It's interesting, in that it can be done. However, in a > > > case like the above it requires intantiaing a new object for dealing > > > with type. > > > > > class X > > > ... > > > def go > > > @ary.each { |x| > > > TypeRunner.new(x).run > > > } > > > end > > > end > > > > > class TypeRunner > > > ... > > > end > > > > > X.new(['a', 'b', 'c']).go > > > > > Am I right about this being thread safe(r) where the first version was > > > not? > > > > Yes, this is thread safe... each thread that calls #go gets its own > > set of objects (TypeRunners) that are separate from the objects in the > > other threads. > > > > > Also, I was thinking. If it's thread safe to just pass type as an > > > argument, one would think there could be a way to define a "locked" > > > instance var that is essentially the same thing but without all the > > > overhead. > > > > It seems like it should be simple, but there's a lot of complexity > > when programming multithreaded code. In your example you're not > > changing the state of anything, so that's why you can simplify > > things... but things get out of hand fast. See my comments past the > > end of the code below. > > > > Here's my attempt at a very *simple* way to do what you're talking > > about... I had trouble getting the methods put in the right namespace, > > so maybe my module code isn't the most elegant but it does what I want > > it to do. > > > > require 'thread' > > > > module Locker > > def self.included mod > > (class << mod; self; end).instance_eval do > > > > define_method(:attr_locked) do |*names| > > class_eval do > > @@locks ||= {} > > > > names.each do |name| > > # make a lock for each attribute > > @@locks[name] = Mutex.new > > > > # getter > > define_method(name) do > > @@locks[name].synchronize do > > instance_variable_get("@#{name}") > > end > > end > > > > # setter > > define_method("#{name}=") do |value| > > @@locks[name].synchronize do > > instance_variable_set("@#{name}", value) > > sleep 5 > > end > > end > > > > end > > > > end # class_eval > > end # attr_locked > > > > end # instance_eval > > end > > end > > > > class DooWop > > include Locker > > attr_locked :chord, :name > > > > def initialize name, chord > > @name, @chord = name, chord > > end > > end > > > > x = DooWop.new('The Platters', 'Fmaj6/9') > > > > $stdout.sync = true > > def tprint string > > print "#{Thread.current} #{string}\n" > > end > > > > Thread.new{ tprint "1. #{x.name}" } > > > > # this will block access to x.name for 5 seconds > > Thread.new{ tprint "2. setting name"; x.name = 'The Orioles' } > > > > # this will wait for the above thread to finish > > Thread.new{ sleep 1; tprint "3. #{x.name}" } > > > > # this isn't blocked > > Thread.new{ tprint "4. #{x.chord}" } > > > > # this will block access to x.chord for 5 seconds > > Thread.new do > > tprint "5. setting chord" > > x.chord = 'Dm7b5' > > tprint "5. #{x.chord}" > > end > > > > # this could be indeterminite, we didn't wait for the writer to finish > > Thread.new{ tprint "6. unsafe: #{x.instance_eval{@name}}" } > > > > sleep 0.5 until Thread.list.size == 1 # should be joining here instead > > > > This is helpful only in the simplest cases. First it blocks everyone > > while in the getter or setter... ideally we shouldn't make the getters > > wait for the other getters to finish. Next, if you try to read the > > variable more than once in a method, you can still end up with > > different values. > > > > You'd need to wrap the section of code that involves the var in a > > #synchronize block... but wrap the *least* amount of code necessary > > because you want to hurry up and let the other threads do their work. > > There's no way to "automate" that. The code above is only useful in > > the most simple applications. > > > > Further, we've only been talking about one variable at a time. Often > > you'll need to lock several variables, like maybe we are going to look > > up on Google which songs by @name have the chord @chord. We'll need > > to get those values at the *same time* because if we read chord, > > (another thread interrupts here and changes @name), then read name... > > that's a problem, and our "locked" variables can't do anything to > > help. > > > > There was a thread on this list a few days ago with a title like > > "synchronized attr", I only skimmed it but I think they were talking > > about why you can't really boil thread synchronization down to a > > one-size-fits-all solution. There are a few data structures (Monitor, > > ConditionVariable, Queue, etc) that really help out, but there's no > > way to just call some method to magically make your code thread > > safe... yet? > > I was thinking more along the lines of "transparent arguments". Here's > the idea in pseudo-code. I'll represent these "transparent arguments" > via an underscore. > > class Q > > def f > _t = "world" > g("hello") > end > > def g(x) > puts x + ' ' + _t > h("goodbye") > end > > def h(x) > puts x + ' ' + _t > end > end > > Q.new.f > > produces > > hello world > goodbye world > > In effect, _t is being tacked on to the arguments of every call, and > is thus getting passed around just like any other argument, but > without need to explicitly "slot" for it in the method interface. In > effect, transparent arguments are a sort of symbiosis of instance var > and argument. Now, I know that some will see this and think it a > violation of the very purpose of functions, ie. the isolation of name > spaces. However, one should see these as a form of instance var, not > argument --they differ only in that they piggy back on the argument > passing mechanism. > > T. > > >