Instance-variable-like user API

Hi everyone. :slight_smile:

I was wondering if anyone can suggest a better solution to a problem I
am trying to solve than one I have come up with. I am trying to create a
friendly user-facing API for accessing custom remote variables.

To explain, consider the following simple class and code:

---===<<< SNIP >>>===---

class A <SomeBase
def initialize
@v = 1
end

def inc
@v = @v + 1
end

def magic
dosomething(@v)
end

attr_accessor :v
end

a = A.new
a.inc
a.magic

---===<<< SNIP >>>===---

Here we have a variable @v that is available for use in each instance of
the class A. We modify it in the instance, and outside of it.

I would like something similar in a user-facing API, where the user can
create a variable v that they can read from and write to, but the catch
is that “v” itself is actually stored remotely in persistent storage.
Each read requests the value from the server, and each write sends it.
The user will define their own variables (such as “v”), and in
presenting the API I won’t know these in advance. Don’t worry about the
storage aspects, networking, serialisation, and cache issues, these are
all written and finished. I’m just trying to provide a nice interface to
the code I’ve already written such that the user can almost ignore the
fact that they are stored remotely.

I’ve written my own “magic_accessor” call to add in a “foo” and “foo=”
method for each variable “foo” (much like attr_accessor), for the user
to use. In this case, we’re just using “v”, which generates the “v” and
“v=” methods when I use it. This changes the above code to the
following.

---===<<< SNIP >>>===---

class A <SomeBase
def initialize
self.v = 1
end

def inc
self.v = v + 1
end

def magic
dosomething(v)
end

magic_accessor :v
end

a = A.new
a.inc
a.magic

---===<<< SNIP >>>===---

What I don’t like with the above is that whenever I set v, I have to be
careful to use "self.v = ", rather than "v = " when I
perform assignment, because the latter will just create a local variable
and not call the “v=” method I’ve created. It’s fine when called
externally on the object, but any internal writes need a “self.” prefix.
I’m not keen on expecting the user to do this each time, when using “@v”
equivalent is so much easier to use.

Is there a better way to implement this, such that the user can write
code similarly to the listing at the top? Is there some syntactic sugar
I am unaware of that can be used instead of “self.foo”? The goal is to
make the user API for this nice and simple- I don’t mind if I have to
mess about to make it happen, and I’ve already got a custom
“method_missing”, and adding code to that is no issue.

Cheers,
Garthy

On Thu, Nov 22, 2012 at 8:17 AM, Garthy D
[email protected] wrote:

unaware of that can be used instead of “self.foo”? The goal is to make the
user API for this nice and simple- I don’t mind if I have to mess about to
make it happen, and I’ve already got a custom “method_missing”, and adding
code to that is no issue.

The only solution for this that I can see is to use some kind of
transaction: you open the transaction, store object state, work with
the object and at the end something inspects instance variables and
writes all changed values. But frankly, OR mappers do exist for Ruby,
ActiveRecord is just one of them. So if it is OK to fill in “RDBMS”
for “remote storage” then you could simply use that. Other than that
I’d stick with using the accessor.

Kind regards

robert

Hi Robert,

On 22/11/12 18:25, Robert K. wrote:

writes all changed values. But frankly, OR mappers do exist for Ruby,
ActiveRecord is just one of them. So if it is OK to fill in “RDBMS”
for “remote storage” then you could simply use that. Other than that
I’d stick with using the accessor.

Thanks for that.

I was hoping there might be a way to wrap the accessor-style solution in
some way that I hadn’t thought of, as this particular solution fits in
elegantly with the rest of the code. If it was possible to hook instance
variable (eg. @foo) writes and reads in some way I think I’d approach it
that way- I just don’t know if this is possible.

Having said that, I’ve been weighing up converting things to use a
solution along the lines you mention, most likely through a whitelist or
blacklist of variables to save in the current object, which I push
across periodically (changes only). This is the less elegant solution
from an architectural point-of-view (ie. it’s a good solution, just a
bit trickier to fit in with my existing code), but I’d bet it would be
the easiest to use from a user point-of-view.

In the problem I am trying to solve, ease of use by the user trumps
elegance of expression, so I’m thinking the second solution (ie. the one
in line with your suggestion) might be the best way to go about it.

Cheers,
Garth

Hi Arlen,

On 22/11/12 20:25, Arlen C. wrote:

end
super
end

It makes it a bit more obvious what’s happening. The other benefit of this
method is that it’s not required to declare these with magic_accessor, as whatever
#remote returns can deal magically with #[]/#[]= or #method_missing.

Thanks for putting that together, it’s a good solution- and actually
very close to what I currently have implemented. :slight_smile: I have a dedicated
remote object with “[]” and “[]=” to handle arbitrary variables, and as
you say, there’s no need to declare anything with magic_accessor. It all
happens like magic.

I’d also considered your second suggestion as a possible solution too.
It’s reassuring that people are thinking along the same lines. :slight_smile:

Unfortunately, in use I found the solution a bit awkward. It’s perfectly
fine for simpler methods, but it gets a bit unwieldy when doing anything
complex. At this point I set out to improve it, and ran into the “self.”
shortcoming. At that point I realised I didn’t actually know of a nice
way to improve it without some sort of downside, so I thought I’d post
to the list to get a second, third, and fourth opinion, in case I’d
missed something. :}

Cheers,
Garth

On Thu, Nov 22, 2012 at 3:55 AM, Arlen C. [email protected] wrote:

end
super
end

What I don’t like with the above is that whenever I set v, I have to be
user API for this nice and simple- I don’t mind if I have to mess about to
for “remote storage” then you could simply use that. Other than that

I’m not quite getting the remote thing – is this a ruby-ism, a
variable, a method, what? Doing a google on “ruby remote” doesn’t get
me anything that I can make sense of this.

If you don’t mind them accessing all vars through a name, you could have
an API like:

class A < SomeBase
def initialize
super
remote[:v] = 1
end

def inc
remote[:v] += 1
end

def magic
do_something(remote[:v])
end
end

Or:

class A < SomeBase
def initialize
super
remote.v = 1
end

def inc
remote.v += 1
end

def magic
do_something(remote.v)
end
end

It makes it a bit more obvious what’s happening. The other benefit of
this method is that it’s not required to declare these with
magic_accessor, as whatever #remote returns can deal magically with
#[]/#[]= or #method_missing.

Hi,

On 23/11/12 00:16, tamouse mailing lists wrote:

remote[:v] += 1
def initialize
end
end

It makes it a bit more obvious what’s happening. The other benefit of this
method is that it’s not required to declare these with magic_accessor, as whatever
#remote returns can deal magically with #[]/#[]= or #method_missing.

I’m not quite getting the remote thing – is this a ruby-ism, a
variable, a method, what? Doing a google on “ruby remote” doesn’t get
me anything that I can make sense of this.

The suggestion is essentially to create a Ruby class that uses the array
ops ("[]" and “[]=”) to manipulate the remote user variables, which
coincidentally was in the same style as the present solution at the time
of my original post. :slight_smile:

An implementation for the class Remote might look like this:

class Remote
def initialize …
…
end

def []= a, v
@server.sendVariableWriteMessage a, v
end

def [] a
return @server.sendVariableReadMessage a
end
end

And we create a remote object for each instance of A:

class A <SomeBase
def initialize
super
@remote = Remote.new …
end
…

attr_reader :remote
end

ie. each object has a remote object attached to it, and you use “remote”
explicitly whenever you want to manipulate one of the remotely-stored
variables. For example, the line:

remote[:v] = 1

would use the remote object, call the “[]=” method on it, which would
cause the variable to be sent to the server.

My question is, essentially, what ways could the problem I mentioned in
my original post be solved with user convenience as a goal, and this is
one potential solution.

So, in answer to your question, “remote” isn’t a Rubyism as such, it’s
just the name of the object we’re using, but treating it like an array
(with “[]” and “[]=” ops) is a Rubyism.

I hope this helps. :slight_smile:

Cheers,
Garth