Re: Benefits of everything is an object? Or new sigils?
by Jenda (Abbot) on Mar 02, 2010 at 10:58 UTC
|
How often do you actually end up wanting to add methods to something that started as a plain old datastructure? I think you invent a convoluted solution to a convoluted example.
BTW, you forgot one solution. You do not have to bless the reference to a tied array. There already is a blessed reference under the covers. Get it by tied(@array) and call whatever you need on that.
Jenda
Enoch was right!
Enjoy the last years of Rome.
| [reply] [d/l] |
|
> How often do you actually end up wanting to add methods to something that started as a plain old datastructure?
When it happens and you need to refactor the code, it's a real pain in the @$$ ...
I think you don't see this situation, because you already incorporated all the ugly workarounds necessary.
> I think you invent a convoluted solution to a convoluted example.
Nope, actually I am spending lot's of time planing in advance to avoid this situation. (And I don't think I'm alone)
Other can just calmly start to code and easily react afterwards. That's one of the big advantages of OOP.
> Get it by tied(@array) and call whatever you need on that.
OK so I can extend the tied package with methods intead of creating a new one... well certainly an improvement. Thx! 8)
But do you really consider writing something like this
tied(@employees)->list_actives()
to be more readable than
\@employees->list_actives()
or even
$employees_ar->list_actives()
???
| [reply] [d/l] [select] |
|
No. I consider list_active_employees(\@employees); readable enough.
You have to invest some time at the beginning to design your data structures and objects and decide what should be an object and what should not. If you do and use objects whenever you are not sure a plain old datastructure is enough, then you should be fine. And if you find out later that something should have been an object, then the fact whether you can attach a method or two will be the least of your worries. Sure, it might have been made easier to do so, but if something was designed and used for a long time as a plain, transparent data structure, then all the code accesses it as such. And does things you would not want code to do with the insides of an object. So you either refactor properly or end up with something that's treated neither as an object nor as a datastructure.
Jenda
Enoch was right!
Enjoy the last years of Rome.
| [reply] [d/l] |
|
|
|
|
|
|
|
Re: Benefits of everything is an object? Or new sigils?
by SuicideJunkie (Vicar) on Mar 02, 2010 at 16:57 UTC
|
A program should not be pushing and shifting a pseudo-global from hundreds of locations. Code duplication like that should be avoided by making a subroutine.
Since you naturally put all those similar subroutines close to each other in the code, you can then tell when you've got a critical mass and it has become worth it to fission the code off into a "human resources" object or module. You don't need to refactor a hundred places. You only need to touch the subs, and they are all conveniently located in one place.
PS: Personally, I always use refs unless I know for sure that the array or hash will never be passed around. Makes variables more consistent to use, and easy to pass around. I suppose that means that I *don't* use sigils to determine the type. Instead I use the variable name itself. Singular vs plural, noun vs adjective. As far as arrays vs hashes go, I have found that there is very little overlap between "order is important" and "needs to look up specific entries by name". On the rare occasions where both are needed, it is complex enough to be worth an object and then it supports both so there is no problem.
PPS:
Hopefully there is no confusion between "you can do everything as an object" vs choking TIMTOWDI by making it "you must do everything as an object". The latter would be bad.
| [reply] |
Re: Benefits of everything is an object? Or new sigils?
by james2vegas (Chaplain) on Mar 04, 2010 at 16:25 UTC
|
There are a number of modules for converting hashes to blessed hashrefs with accessors for the elements within, f.e. Data::AsObject and Hash::AutoHash. In this code I imagined you'd be using an %employees hash rather than an array, and keyed it on some imaginary employee id. I then subclassed Data::AsObject::Hash to add a new method to take a reference to the employees hash and create the accessors (through the dao function) automatically.
I was able to add custom methods to my EmployeeData class which can work on $self as either a subclass of Data::AsObject::Hash or as a hashref (or hash, through dereferencing) and you can continue to use the %employees hash as before.
If you wished to use an array, then dao would need to be given a hashref with one key and a reference to the array as the value, e.g. dao { data => \@employees }.
Of course, you could just as easily have created a completely new class, which just blessed \@employees (or \%employees) into $class and just used it as a means to add methods.
If you keep both %employees and $employees in the same scope it would provide a (really ugly) way of keeping the original array|hash and its blessed reference and using, f.e., both push @employees, { name => 'Foo Bar' }; and $employees->method_call; in the same code, though hopefully at some point you'd switch over to just the object/reference.
I don't this is some 'problem' which requires the use of slow modules like autobox or some wholesale re-invention of Perl symbology. Just some reasonable amount of pre-planning and willingness to make reasonable, incremental changes in existing code.
| [reply] [d/l] [select] |
|
As far as I understand these packages simplify the workaround I sketched...
> If you keep both %employees and $employees in the same scope it would provide a (really ugly) way of keeping the original array|hash and its blessed reference
yeah indeed ugly, thats what I meant.
> I don't this is some 'problem' which requires the use of slow modules like autobox ...
Contrary to the believe of the group that flames against me, I'm not propagating autobox as an existing solution! (I was asking a question in another thread about autobox and hit the nerve of a group of united fanboys. But I'm tired to repeat this!)
I was talking about the theoretical benefits JS has over Perl in this respect, because there a hash acn be treated as object right from the beginning.
Tieing this hash provides the same functionality in Perl like altering the object in JS (Phase 2)
BTW: According to the docs, autobox isn't slower than method calls on blessed references.
>or some wholesale re-invention of Perl symbology.
A Sigil for each Ref-Type would open a lot of simplifications for problems newbies face when starting to learn Perl.
Believe it or not, many people stop and hate Perl just because of these problems...long before even entering a level allowing to understand Data::AsObject and Hash::AutoHash.
Many thanx for your contribution, it's one of the better ones lifting the level of this discussion! :)
| [reply] |
|
In a way you could say there is a sigil for each ref-type, when it gets deferenced (or when it is actually used as the base type, and not a reference in a scalar), @ => @$, % => %$, & => &$.
For amusement or other purpose, here is code that lets you use a hashref or hash (or arrayref or array) by blessing the former (and the ref of the latter) into an (initially) non-existent package, and then create a function in that package. The function can be called in the usual way ($blessedref->function), but can also be called with NameSpace::function(%indirectlyblessedhash) owing to the \% prototype on the function which uses the reference of that parameter.
If you use references for your data structures instead of plain hashes and arrays, and bless those references into appropriate packages (and dereference where needed), you will have the equivalent functionality to javascript array|objects. For me, at least, the requirement (softened by autobox), that objects be scalars makes sense, as scalars are for holding one value (base type or object) at a time.
| [reply] [d/l] [select] |
|
Re: Benefits of everything is an object? Or new sigils?
by Xiong (Hermit) on Mar 06, 2010 at 10:03 UTC
|
Upvoted the OP, as it's an interesting meditation; but I disagree with most of it. In the Bad Old Days, if you found out you needed a 12-column string variable after you'd allocated 10 bytes of storage, you were toast.
Planning your data structures must come early in any project. I feel that if you find you need to revise extensively your data structures, you need to reconsider your entire approach. If it's just a matter of hanging one bag onto the existing structure then it's likely just writing another subroutine. If it's more than that, then it may well be time to throw out a lot of code and start over. I don't say that can't be painful.
That's why I spend so much time sketching data structures on paper before I touch the keyboard. By no means do I avoid all later redesign; but I try to cut down on the number of slash-and-burn incidents. When I fail, I refactor. Perl makes it very easy to minimize the damage from poor planning but I don't want to lacquer any real mistakes into the project's frame.
I don't hold with making every variable an object; that's fanaticism when carried to an extreme. (Here is a somewhat fanatic criticism.) I do use objects when they make sense: when I'm passing something persistent around, or working on it in many scopes, and especially when there's a natural hierarchy of classes in the data. I avoid creating verb or adjective objects; they don't make sense.
OP's point about sigils is well taken. One reason to avoid too many objects is to keep all variables from looking alike. But I'd argue against any change in syntax, any additional sigils. I don't rely on sigils to tell me what a variable contains; I expect them to tell me in what context an expression is evaluated. I do not usually employ both $foo and @foo in one place, or even one project. I don't welcome the Perl6 syntax in which %foo{3,4} is a hash slice.
I would also argue that one ought not use blessed array refs as objects. Traditional (if I may use the word) Perl objects are blessed hashrefs, with it being understood that these may well point to HoH, HoA, or more complex structures. More modern objects (again, if I may be excused) are the flyweight (inside-out) kind. While any code might use an older module (with traditional objects) but create modern objects, I'd hope that all objects created in a given project be of the same kind, one or the other.
We should not cavil at contrived examples; they're often better in discussion than the whole nasty real thing. But I have a difficult time with a plural object. When I'm in doubt, I try it in English: "Have an @employees"; "My @employees is an object in class ____". Maybe not so much. Calling an object, a data structure which is basically an array, violates the common understanding that an object is a thing belonging to a class and to which attributes pertain. A glass may contain many marbles but those marbles are but one attribute of the glass. A $roster may be an object; $roster->get_names_of($active) may return an array -- possibly of objects. Nor is there any objection to assigning that to the small-scoped @employees.
Conway is not generally in favor of bumps but if you feel you need to clarify, I won't object to $roster_obj or _ref. If you really do feel you need a blessed array ref, I'd like to see $employees_aryobj; it's fair warning.
On the same page, I'd like to mention an old guy who debugged all code by placing a sheet of paper on the right side, covering the comments. He wasn't interested in what the author said the code would do. Again, I expect the sigils only to tell me what will happen; not what the author's intent may have been. For the latter (since I'm not that good), I'll read the comments.
I intend no offense to say that the example given wants to have OO cake and eat it as well. I would not try to push() anything into an object. If I needed to do that, I'd $roster->push($new_guy); or better, $roster->hire($new_guy) or perhaps $new_guy->hire($roster).
If all you have is object orientation then everything looks like an object.
| [reply] [d/l] [select] |
|
Thanks for this reply, it deepens the meditation into new dimensions worth at least one new thread. :-)
Unfortunately I can't spend as much time to reply here like I did for other posts in this thread.
> That's why I spend so much time sketching data structures on paper before I touch the keyboard.
So do I, but sometimes its better to just start to code with the intention to prototype the real thing.
And even in prototyping the Javascript approach is less painful than Perl.
> I would also argue that one ought not use blessed array refs as objects.
I disagree, maybe I'm too influenced by Conways OOP book but I see Perls possibility to bless any ref as the advantage of this (maybe too?) flexible OO System.
After tieing the array to a new class, push() will act however you want it to act, e.g. the data can be easily inside out. I can't see why a blessed arr_ref should act differently to a blessed hash_ref, so no need to worry about ugly side effects.
> But I have a difficult time with a plural object.
IMHO this "plural naming convention" is a workaround for missing sigils. Actually I spend too much time to invent clear plural names where I would prefer to simply set a sigil.
Normally I have my own hungarian notation writing something like $A_employees or $employees_ar to denote the nature of the variable. Contrary to PBP I prefer the former, because I want to know what I'm dealing with at one glance and _one_ end of the word , not on both ends. And Perl favors the beginning...
> I expect the sigils only to tell me what will happen; not what the author's intent may have been. For the latter (since I'm not that good), I'll read the comments.
I agree to a certain point, the sigils should be very clear about context and data type.
I think mentioning Perl 6 was misleading...I'm also not happy about hash-slices which start with a $! :(
In my vision these sigils should only be in scalars context, such that €employees == $employees is always true.
The differences I'm meditating of are
I see plenty of advantages in this approach...
¹) this is a contrived example, I know that a hash with key "phonenumbers" is a better choice than using an array with an index $idx_phonenumbers! :)
²) there's another possibility to be mentioned, IIRC Perl 6 allows a slice to be called with "method syntax" ->@[LIST] (of course in Perl6 with a point and not an arrow ;)
| [reply] [d/l] [select] |