Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^3: Serious Exporter Problems

by etcshadow (Priest)
on Jul 10, 2005 at 16:19 UTC ( #473762=note: print w/ replies, xml ) Need Help??


in reply to Re^2: Serious Exporter Problems
in thread Serious Exporter Problems

Well, as to the bit about the arguments... they've really not been about questions of circular dependancies, but rather about the specific question at hand (importing from a module that imports from you), and the necessity of setting up of your exports at compile-time. That's why I happened to have a fairly detailed example of this imediately at hand.

As to the outright condemnation of circular-uses, I have to respectfully disagree. In managing a complex project, it can become a fairly arbitrary line to draw between your modules. It forces you to structure your code-containers around your code's calling-graph, rather than around the functional nature of your code.

I spend most of my time writing code for healthcare, so here is a simplified example: I want to be able to group code for patients in a Patient module, and code for claims in a Claim module. There are perfectly reasonable cases which require the processing of a claim to have to access patient functions, and vice-versa. Patient's have claims, and the description of a patient is not complete without his/her claim-history. When displaying a claim, I need to access the patient's information, as it is a fundamentally important part of the claim. If I understand your "circular uses are bad, 'mkay" correctly, then I should not be allowed to organize my code this way.

Also, as to the comment that other languages do not allow circular dependancies, that's just not true (in my experience). Certainly *some* other languages will not have a means to allow for it... but *some* other languages do all sorts of crazy things and impose limitations that I don't ever want to deal with as a user of that language. Even a language which provides as little in the way of facilities to the programmer as C has a means for dealing with circularly dependant libraries. First, there is a separation between headers and code... that goes a long way, on its own. Second, a fairly simple method for preventing pre-compiler infinite-loops is employed:

#ifndef some_token_i_use_to_represent_this_file #define some_token_i_use_to_represent_this_file 1 /* your code goes here */ #endif

So, C, and any language which inherits it's basic separation of header files and code files from C, along with a pre-compiler as capable as C's is set. It can handle circular dependancies.

I guess that gets somewhat to a larger point about this question (as well as some of the issues you raised with circular uses in perl): different languages do things differently with respect to this, and in many of them (all, maybe), there is a necessary discipline to build atop the language, itself, to protect yourself from problems. In perl, this discipline includes understanding the difference between BEGIN time and run-time, and using that understanding appropriately. Maybe perl requires a little bit too much in the way of requiring discipline from its programmers, in this regard... on that I won't comment. It certainly wouldn't be the first time perl's been accused of requiring self-discipline of its programmers, rather than enforcing discipline upon them.

However, I actually don't think that there is anything all that wrong with publishing some best practices as a way to encourage that self-discipline in people who haven't yet attained the understanding of why that self-discipline is necessary. In my mind, telling people to always put their @ISA and @EXPORT setup in a BEGIN block is kind of like telling people to use strict. Actually, a better comparison would be like telling people to NEVER put a "my" operator in a conditional. The reason why it's important to do this is tricky to divine on your own, and may not bite you imediately. Still, there's no harm in doing it, and it may (proably will) prevent errors, later.

------------ :Wq Not an editor command: Wq


Comment on Re^3: Serious Exporter Problems
Select or Download Code
Re^4: Serious Exporter Problems
by Tanktalus (Canon) on Jul 10, 2005 at 16:51 UTC

    My solution is to put everything in objects. I get a lot fewer problems that way. X, Y, and Z may all use each other indiscriminately, but because there are no exports, I get no problems. Best of all worlds ;-)

    (I'm not using B as an example because we've run into that problem before - just like using $a and $b as example variables gets some unexpected side effects, B as an example package name can get some (rare) unexpected side effects as well.)

Re^4: Serious Exporter Problems
by tilly (Archbishop) on Jul 10, 2005 at 19:59 UTC
    Let's see.

    You ignored the alternate require solution. You ignored the error reporting issues with BEGIN type games which argue for not playing them. You dismiss the existence of languages that don't handle circular dependencies. (I believe that PL/SQL is one.) You don't seem to be aware that your solution doesn't solve all of the issues with circular dependencies in Perl. (Example, suppose in your example that a Patient has claims, and a claim has a Patient. Both of those are cached for efficiency. Guess what? You have a memory leak!)

    As for your example, there are plenty of ways of handling this. For instance you can have a module that you're supposed to use which does all of the other uses for you, in the right order. Or you can use an OO style which avoids the need to export anything and makes circular dependencies not quite as bad. Or you can use lazy loading so that dependencies are resolved as they're about to be called. And often you can find a design which avoids the circular dependency entirely. (Rule of thumb, in a good design each module will call few others, but will be called from many other places. If this is achieved, then circular dependencies become unlikely.)

    Any of these solutions can be sufficient. All of them avoid having to think hard about compile vs runtime. All of them avoid the error reporting problems that I pointed out can happen with BEGIN games.

    Given the existence of alternatives, I'd prefer to not make recommendations that make code more complex and cause problems of their own for the possibility that someone will create grief. Instead I'd prefer to suggest the discipline of avoiding creating circular dependencies, and then let people know what problems they create when you do cause them.

      tilly,

      you are one of the most experienced monks here at the monastery and from not only the number of your posts but also their content one can be quite sure, that your "highscore-position" here pretty much correlates with your perl skills.

      I do not know what previous issues you might have had with etcshadow, but I'd like to look at this thread without considering them. If I do, I see on the technical side very many precious facts and alternatives to our problem, on the other side I see many IMHO unnecessary attacks against etcshadow. Sure, the BEGIN "solution" might bring complexity to the code and later on even more subtle problems that'd be absolutely hard to tackle.

      OTOH we took his advice "put everything into BEGIN" more lika a rule of thumb exactly as yours "every module should load a few modules and be loaded by many".

      In fact etcshadows advice

      • was the first answer that came in and it contained a real solution for our problem. The system compiled again within minutes.
      • it was good for us, because it gave us something to think about, as this was a blind spot in our design. Before we had an attitude "perl is great it will handle this somehow" - even circular references. Hell it worked for more than five years!
      • by thinking about it, we were able to deduct the "badness of circular reference" even before your post came in.
      In short, his answer was valuable for us. By providing your comments on that matter, we got everything one can only hope for - a thorough and detailed view on this matter.

      We see both contributions as valuable, perhaps even the value comes only with some argues, but let me state, that some of your formulations remind me of merlyn when he - undoubtedly also a perl capacity - got beaten by seemingly being too harsh in his comments.

      Bye
       PetaMem
          All Perl:   MT, NLP, NLU

        I haven't had previous problems with etcshadow.

        But I hate it when people give categorical advice that I think is bad, particularly when they know full well that very competent people disagree with them! If you know that people disagree with you, understand the disagreement and respect it. Sure, go ahead and offer the advice but make it clear that it is what you personally like to do. Don't take the attitude, This is what everyone should do and I can't believe that some experienced people have been stupid enough to argue with me. That's guaranteed to not sit well with any experienced person who does not agree with you.

        Which is what happened.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://473762]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (9)
As of 2014-07-14 07:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (256 votes), past polls