

Charging Objects in Ruby - judofyr
http://timeless.judofyr.net/charging-objects-in-ruby

======
djacobs
I don't get the appeal of coding like this. To me, a unary operator shouldn't
mutate its receiver. (Edit: neither should a binary one.) Instead, the
resulting value is meant to be assigned to a new value or otherwise
manipulated.

This is a sort of DSL, but it doesn't really give us any more clarity than
traditional allow/disallow arrays, does it?

It's this:

    
    
      + url("your-url-here")
    

versus this:

    
    
      allowed << url("your-url-here")
    

Why is the former more attractive?

~~~
tptacek
As a programming construct, it isn't.

As a configuration language, it might be.

~~~
masklinn
Bingo. It's executable code that reads like a config file, that's about as
good as configuration can get.

~~~
djacobs
What's the use case, though? If you want config file syntax, use a config
file. If you want a program, use code.

Building up an object system like this for simple configuration seems
excessive to me.

I would do something like this:

    
    
      c = YAML.load_file 'config.yml'
      allowed, disallowed = c['allowed'], c['disallowed']

~~~
masklinn
> What's the use case, though? If you want config file syntax, use a config
> file. If you want a program, use code

Data is code is data, avoids having to write a parser (or even reuse an
existing one), avoids having to resolve the impedance mismatch between the
programming language and the configuration language, scales up infinitely in
case the user needs more power (which is not that rare, especially for a rules
system which is the use case here)

> I would do something like this:

> c = YAML.load_file 'config.yml' > allowed, disallowed = c['allowed'],
> c['disallowed']

Now you have two superfluous lines in your code and you have not gained
anything of value.

~~~
djacobs
I don't have any superfluous lines in my code. I wanted to load a config file
into my runtime, and I did. Not superfluous at all. The (extraordinarily)
superfluous code is the code used to set up the object config system where
none is needed.

> Data is code is data.

This is hardly a case of homoiconicity, is it?

~~~
masklinn
> Not superfluous at all. The (extraordinarily) superfluous code is the code
> used to set up the object config system where none is needed.

You need that code to load/create rules in any case, but for you it's done
from a config file which the user writes. For TFAA, the user loads his data
directly into the running system. Therefore the layer _you_ have to setup
between the config file and the actual running code (parsing the config file
then interpreting its values to translate them into a running ruleset) is
superfluous: you can do without it.

Because you know, your "example" YAML parsing is useless in and of itself, it
doesn't result in a working ruleset, you skipped the whole part where you feed
that data to your code and setup the stuff that actually does work.

TFAA removes the parsing and interpretation from the chain and instead lets
the user feed data directly to the running code without layers inbetween.

~~~
djacobs

      Because you know, your "example" YAML parsing is 
      useless in and of itself, it doesn't result in a 
      working ruleset, you skipped the whole part where you 
      feed that data to your code and setup the stuff 
      that actually does work.
    

Sorry, but that's not actually the case, is it? There is no "business logic"
in his example. To actually use the config system he's set up, you need to
evaluate Rule#charge for every rule you want to evaluate. In my example, all
you could run allowed.include? or simply iterate over the allowed array.

------
tres
Maybe I just don't 'get it;' to me, this is that dark underbelly of Ruby's
Perlness oozing out.

Magic operators are one of Perl's worst features & now we can make them even
worse in Ruby by creating our own set of unmaintainable overloaded magic
operators. Everyone can create their own private hell to invoke on every other
Ruby coder!

Put down teh overloaded magic operators and step away from the keyboard.

:)

Anyway, thanks for the post & for your blog in general; lots of helpful, well
written articles.

~~~
extension
To those who are accustomed to languages without operator overloading, they
are magic. To the rest of us, they are just method names plus a bit of special
syntax.

~~~
tres
It's not that I'm not accustomed to them or don't know how to use them. It's
that I believe they are the embodiment of bad coding practices. They are
esoteric shortcuts that make code easy to write and much harder to maintain.

They are here-and-now solutions that ultimately cost more time and effort in
the long run.

Because some Perl coder wanted to type

$>

instead of spending a fraction of a second more and type

$EUID

anyone attempting to use that code forever after needs to address the micro
meanings of the syntax itself. There's no expressiveness in the syntax, no way
to understand the complex meaning of the operator without a reference.

These operators are dramatically different than basic operators. They require
much more context and are much less intuitive.

I know the other side of this argument is that it's akin to learning any other
syntax of a language. I can understand the argument and I don't disagree. But
personally, I find the maintainability of any code drops off a steep cliff
once it starts using magic operators.

Personally, I want to deal with finding solutions to problems, not deal with
the esoteric symbols that have been arbitrarily associated with some abstract
and complex concept.

I know immediately when I look at Ruby's

Process.euid

what we're dealing with.

Not so much when I see

$<

or is it

$>

hmm... let me go look that up...

~~~
extension
+/-url("...") in the context of a DSL for building allow/deny rulesets is
considerably more self-descriptive than your example from another language
that isn't even an operator, just a badly named variable.

Personally, I would have gone with allow/deny instead of +/- but I'm glad the
choice is available. It certainly pays off for numeric types or DSLs that
involve complex nested expressions e.g. parsing grammars.

~~~
tres
Fair enough. I was pretty fast and loose. Thanks for the correction.

My magic vars/operators mix & match was inaccurate, but still appropriate; the
point still remains, overloading operators seems risky for long term
maintenance if it's not used cautiously.

It's clever & no doubt has its usefulness, but as the author of the article
implies, it can be (ab)used. And I guess I hopped off the train right there.

I think I'll take a look at this again tomorrow with fresh eyes & see what I'm
missing.

Thanks again for the correction.

------
draegtun
End of work day boredom is here so I thought I take a crack at doing this in
Io: <https://gist.github.com/748656>

The "DSL" part looks like this:

    
    
        Rules do (
          + url("http://timeless.judofyr.net/*")
          - url("http://timeless.judofyr.net/")
          - url("http://timeless.judofyr.net/changelog/*")
        )

