refactoring

Discussion in 'Java' started by Roedy Green, Aug 6, 2007.

  1. Roedy Green

    Roedy Green Guest

    I often run into this situation and wonder if there are clever ways of
    handling it I have not thought of.

    I have a hunk of messy code I would like to break off from a method
    and make into its own small method. I use Intellij refactoring
    "Extract Method" but it tells me I can't do that because the code
    fragment has multiple outputs, e.g. computing two or three static
    final local booleans.

    I have always felt that a if a method can have multiple inputs it
    should be able to have multiple outputs, but very few language
    designers (Forth and PostScript being exceptions) have agreed.

    It seems such a production to wrap three booleans as if for transport
    to Africa in their own class, in an array, (not to mention the
    unpacking code) when at the machine level what I am doing is trivial
    in assembler..
    --
    Roedy Green Canadian Mind Products
    The Java Glossary
    http://mindprod.com
     
    Roedy Green, Aug 6, 2007
    #1
    1. Advertising

  2. Roedy Green

    Eric Sosman Guest

    Roedy Green wrote On 08/06/07 16:19,:
    > I often run into this situation and wonder if there are clever ways of
    > handling it I have not thought of.
    >
    > I have a hunk of messy code I would like to break off from a method
    > and make into its own small method. I use Intellij refactoring
    > "Extract Method" but it tells me I can't do that because the code
    > fragment has multiple outputs, e.g. computing two or three static
    > final local booleans.
    >
    > I have always felt that a if a method can have multiple inputs it
    > should be able to have multiple outputs, but very few language
    > designers (Forth and PostScript being exceptions) have agreed.
    >
    > It seems such a production to wrap three booleans as if for transport
    > to Africa in their own class, in an array, (not to mention the
    > unpacking code) when at the machine level what I am doing is trivial
    > in assembler..


    Lots of things are easy in assembly code but difficult
    in higher-level languages: unrestricted GOTO, type-punning,
    self-modifying code, ... But yes: Some far less iniquitous
    things are also hard to do: Getting both the quotient and
    the remainder from one integer division, for example, which
    is perhaps the situation in which I most miss multiple-valued
    expressions.

    The only way I know to deal with such issues (without
    the bother of inventing a "container" of some kind) is to
    study whether the computations of the two or three things
    can be untangled from each other. Sometimes they are too
    intimately connected to be divorced: like the quotient and
    remainder, for example. But quite often they can be pulled
    apart so that the messy code divides into multiple methods,
    each returning one of the values.

    One avenue that is sometimes fruitful -- especially with
    flags, for some reason -- is to reconsider the data being
    computed. Can the data items themselves be "orthogonalized"
    by representing the same information differently? Maybe the
    three flags really ought to be one enum, for example.

    --
     
    Eric Sosman, Aug 6, 2007
    #2
    1. Advertising

  3. Roedy Green

    Chris Guest

    Roedy Green wrote:
    > I often run into this situation and wonder if there are clever ways of
    > handling it I have not thought of.
    >
    > I have a hunk of messy code I would like to break off from a method
    > and make into its own small method. I use Intellij refactoring
    > "Extract Method" but it tells me I can't do that because the code
    > fragment has multiple outputs, e.g. computing two or three static
    > final local booleans.
    >
    > I have always felt that a if a method can have multiple inputs it
    > should be able to have multiple outputs, but very few language
    > designers (Forth and PostScript being exceptions) have agreed.
    >
    > It seems such a production to wrap three booleans as if for transport
    > to Africa in their own class, in an array, (not to mention the
    > unpacking code) when at the machine level what I am doing is trivial
    > in assembler..


    I've often wondered the same thing. Fortunately, with modern garbage
    collectors creating a wrapper class is not that expensive.

    Another method I sometime use is to pack returns in an int or long. For
    your boolean example, you can set bits in an int and return it. Ugly,
    but fast. Somewhat less ugly, when I need to return two ints I'll pack
    them into a long.
     
    Chris, Aug 6, 2007
    #3
  4. Roedy Green

    Michael Jung Guest

    Roedy Green <> writes:
    > I often run into this situation and wonder if there are clever ways of
    > handling it I have not thought of.


    We don't knowwhat you have already thought of.

    > I have always felt that a if a method can have multiple inputs it
    > should be able to have multiple outputs, but very few language
    > designers (Forth and PostScript being exceptions) have agreed.


    Corba IDL is another and the corresponding compilers generate Java code,
    illustrating how this is done in Java alone. Holder classes. Has the
    disadvantage of not forcing you to return something.

    Otherwise, I agree. Multiple return values without the overhead would be
    nice.

    How about something along

    "public double,double calcModAngle(double re, double im);" ?


    Michael
     
    Michael Jung, Aug 6, 2007
    #4
  5. Roedy Green

    Stefan Ram Guest

    Roedy Green <> writes:
    >should be able to have multiple outputs, but very few language


    One idea not mentioned yet is a kind of »continuation passing
    style« (»actor style«). The client's method »continuation« is
    called by the server to »return« the result. Here the client
    gets /two/ random numbers from /one/ call to »getPair« without
    an object or an array holding these two numbers.

    class Example implements Client
    { public void continuation( final int x, final int y )
    { java.lang.System.out.println( x + ", " + y ); }
    public void main()
    { Server.getPair( this ); }}

    class Server
    { static java.util.Random rand = new java.util.Random();
    static void getPair( final Client client )
    { client.continuation( rand.nextInt( 11 ), rand.nextInt( 21 )); }}

    public class Main
    { public static void main( final java.lang.String[] args )
    { new Example().main(); }}

    interface Client { void continuation( int x, int y ); }

    4, 3

    When the program does not need to be threadsafe, the function
    and its result can be made static and public to avoid any
    overhead by object allocation and getter methods.

    public class Main
    { public static void main( final java.lang.String[] args )
    { Calculator.x = 1;
    Calculator.y = 2;
    Calculator.sumDiff();
    java.lang.System.out.println( Calculator.sum );
    java.lang.System.out.println( Calculator.difference ); }}

    class Calculator
    { public static int x;
    public static int y;
    public static int sum;
    public static int difference;
    public static void sumDiff(){ sum = x + y; difference = x - y; }}
     
    Stefan Ram, Aug 6, 2007
    #5
  6. Roedy Green wrote:
    > I often run into this situation and wonder if there are clever ways of
    > handling it I have not thought of.
    >
    > I have a hunk of messy code I would like to break off from a method
    > and make into its own small method. I use Intellij refactoring
    > "Extract Method" but it tells me I can't do that because the code
    > fragment has multiple outputs, e.g. computing two or three static
    > final local booleans.
    >
    > I have always felt that a if a method can have multiple inputs it
    > should be able to have multiple outputs, but very few language
    > designers (Forth and PostScript being exceptions) have agreed.


    Matlab is another exception.

    > It seems such a production to wrap three booleans as if for transport
    > to Africa in their own class, in an array, (not to mention the
    > unpacking code) when at the machine level what I am doing is trivial
    > in assembler..


    I try not to think in assembler when coding in Java, or think in Java
    when coding in Matlab... Most languages have some things that can be
    said simply and directly, and other things that take longer.

    For the specific case of three booleans, I would question whether there
    should be an enumeration naming the conditions, with the method
    returning an EnumSet.

    However, I'm sure you don't just mean the specific case of booleans.

    If the code only runs in one thread, it can sometimes be helpful to
    first convert the local variables to fields. That allows the method
    extraction. Sometimes, further refactoring comes to light after the
    extraction that gets rid of the fields again.

    Patricia
     
    Patricia Shanahan, Aug 6, 2007
    #6
  7. On Aug 6, 9:19 pm, Roedy Green <>
    wrote:
    > I often run into this situation and wonder if there are clever ways of
    > handling it I have not thought of.
    >
    > I have a hunk of messy code I would like to break off from a method
    > and make into its own small method. I use Intellij refactoring
    > "Extract Method" but it tells me I can't do that because the code
    > fragment has multiple outputs, e.g. computing two or three static
    > final local booleans.
    >
    > I have always felt that a if a method can have multiple inputs it
    > should be able to have multiple outputs, but very few language
    > designers (Forth and PostScript being exceptions) have agreed.
    >
    > It seems such a production to wrap three booleans as if for transport
    > to Africa in their own class, in an array, (not to mention the
    > unpacking code) when at the machine level what I am doing is trivial
    > in assembler..
    > --
    > Roedy Green Canadian Mind Products
    > The Java Glossaryhttp://mindprod.com


    Hi Roedy,

    The others have discussed the multiple returns values PoV, so I'll
    just mention about the refactoring itself.

    When IntelliJ/Eciplse moans about 'multiple outputs', its usually one
    of two signs:
    1) I'm trying to pull too much into a single method, and so to fix
    this, pull 3 (in your example) sets of smaller code into 3 smaller
    methods.

    2) The ordering of the variables being used within the original
    method are preventing the extraction. To fix this, re-arrange the code
    within the original method so that the new method does not need to
    return 3 outputs, but instead it can then return a different value.

    Feel free to post your original method if you'd like me to show you
    what I mean using your code.

    HTH


    Andrew
     
    andrewmcdonagh, Aug 6, 2007
    #7
  8. Roedy Green

    Michael Jung Guest

    -berlin.de (Stefan Ram) writes:
    > Roedy Green <> writes:
    > >should be able to have multiple outputs, but very few language

    >
    > One idea not mentioned yet is a kind of »continuation passing
    > style« (»actor style«). The client's method »continuation« is
    > called by the server to »return« the result. Here the client
    > gets /two/ random numbers from /one/ call to »getPair« without
    > an object or an array holding these two numbers.


    I think this solution is for a trip to Africa, as Roedy originally put it:)

    > When the program does not need to be threadsafe, the function
    > and its result can be made static and public to avoid any
    > overhead by object allocation and getter methods.

    [...]

    One of the things that always strikes me is that explains a lot of inefficient
    code. Here's an example held artificially simple.

    double a = above(x);
    double b = below(x);

    double above(double x) { return (int)(2*Math.abs(Math.sin(x)))/2.0; }
    double below(double x) { return 1 - above(x); }

    vs.

    double a,b = aboveandbelow(x);

    double aboveandbelow(doubl x) {
    double t = (int)(2*Math.abs(Math.sin(x)))/2.0;
    return t, 1 - t;
    }

    It should be obvious that calculating individually is more costly
    than as a whole. (*)

    But as code evolves, you suddenly find out you need need more results from a
    method than before. Sometimes refactoring takes place at the right time, but
    sometimes it doesn't and you are either stuck with two methods doing the
    almost the same thing or one method returning an "arbitrary" array.

    (*) And yes, I am aware that b = 1 - a in the first case. But what if you do
    not really know the implementation?) I'm pretty sure that a lot of methods
    even in the JDK Java packages show this problem, just because it would have
    broken the developper's heart to create an auxiliary class to return two
    results., say in- (The whole point construct in Swing could be seen as a point
    in case as well. There's a lot of garbage floating around.)

    Michael
     
    Michael Jung, Aug 7, 2007
    #8
  9. Roedy Green

    Roedy Green Guest

    On Mon, 06 Aug 2007 22:03:10 -0000, andrewmcdonagh
    <> wrote, quoted or indirectly quoted someone
    who said :

    >Feel free to post your original method if you'd like me to show you
    >what I mean using your code.


    Here is the code I am trying to tidy up. Of course my mind goes blank
    on all the other code I either tidied or attempted to tidy with a
    similar "multiple outputs" problem.

    This is a method from the static macros. It is used to expand
    something like
    <!-- macro Sun "JButton" docs/api/javax/swing/JButton.html -->
    to
    <div class="sun">Sun's Javadoc on the <span
    class="jclass">JButton</span> class : available:
    <ul>
    <li>
    <a class="offsite"
    href="http://java.sun.com/javase/6/docs/api/javax/swing/JButton.html">on
    the web at java.Sun.com</a></li>
    <li>
    <a
    href="file://localhost/J:/Program%20Files/java/jdk1.6.0_02/docs/api/javax/swing/JButton.html">in
    the JDK 1.6.0_02</a> or in the older <a
    href="file://localhost/J:/Program%20Files/java/jdk1.5.0_12/docs/api/javax/swing/JButton.html">JDK
    1.5.0_12</a> or the even older <a
    href="file://localhost/J:/j2sdk1.4.2_15/docs/api/javax/swing/JButton.html">JDK
    1.4.2_15</a> on your local <a class="plain" href="jdrive.html">J:
    drive</a>.</li>
    </ul>
    </div>



    /**
    * guts to Generate reference to a Sun HTML document.
    *
    * @param fileBeingProcessed File being processed that contains
    the macro to
    * be expanded.
    * @param desc human descriptinon of what it is.
    * @param ref reference e.g
    api/java/awt/package-summary.html
    * /s or \s. Generates
    http://java.sun.com/j2se/1.6.0/docs/api/java/awt/package-summary.html
    *
    * @return expand href both to on-line and local.
    *
    * @noinspection WeakerAccess
    */
    public static String expand( File fileBeingProcessed,
    String desc,
    String ref )
    {
    /* chop lead / if any */
    char firstChar = ref.charAt( 0 );
    if ( firstChar == '/' || firstChar == File.separatorChar )
    {
    ref = ref.substring( 1 );
    }

    /** reference with / instead of File.separatorChar . partial
    or complete url.
    * May be extended in following code.
    */
    String refWithSlashes = ref.replace( File.separatorChar, '/'
    );
    /**
    * short description with bold html applied.
    */
    final String boldDesc = "<b>" + desc + "</b>";
    /**
    * expanded description
    */
    final String longDesc;
    /**
    * Are the docs also locally available in the recent JDK docs?
    *
    * JDK 1.6 has directories api, jdk, jre, legal, platform,
    technotes
    * jdk 1.5 guide*, relnotes*, tooldocs*, no longer avail.
    Still has api.
    */

    final boolean localRecent;
    /**
    * Are the docs available in old locally available JDK docs?
    */
    final boolean localOld;

    /**
    * true on Sun's site is this a reference to the
    * http://java.sun.com/javase/6/ directory.
    * False, implies http://java.sun.com/
    */
    final boolean javase6;

    // expand forms where don't supply full URL.
    refWithSlashes = expandAbbreviations( refWithSlashes );

    // deal with long forms
    if ( refWithSlashes.startsWith( "docs" ) )
    {

    if ( refWithSlashes.startsWith( "docs/books" ) )

    {
    // Only on sun site, not local.
    javase6 = false;
    localOld = false;
    localRecent = false;

    if ( refWithSlashes.startsWith( "docs/books/codeconv"
    ) )
    {
    longDesc = "Sun's Coding Conventions on " +
    boldDesc;
    }
    else if ( refWithSlashes.startsWith( "docs/books/jls"
    ) )
    {
    longDesc =
    "Sun's JLS (<b>J</b>ava <b>L</b>anguage
    <b>S</b>pecification) on "
    + boldDesc;
    }
    else if ( refWithSlashes.startsWith( "docs/books/jni"
    ) )
    {
    longDesc =
    "Sun's JNI (<b>J</b>ave <b>N</b>anive
    <b>I</b>nterface) Specification on "
    + boldDesc;
    }
    else if ( refWithSlashes.startsWith(
    "docs/books/tutorial" ) )
    {
    longDesc = "Sun's tutorial on " + boldDesc;
    }

    else if ( refWithSlashes.startsWith(
    "docs/books/vmspec" ) )
    {
    longDesc =
    "Sun's VM (<b>V</b>irtual <b>M</b>achine)
    Specification on "
    + boldDesc;
    }
    else
    {
    longDesc = "Sun's Book on " + boldDesc;
    }
    }// end books

    else if ( refWithSlashes.startsWith( "docs/api/" ) )
    {
    // strip any leading the and trailing class
    desc = StringTools.removeHead( desc, "the " );
    desc = StringTools.removeTail( desc, " class" );

    // apply styles to class/method name
    final int dotPlace = desc.indexOf( '.' );
    final String decoratedDesc;
    if ( dotPlace < 0 )
    {
    decoratedDesc =
    "the <span class=\"jclass\">"
    + desc
    + "</span> class";
    }
    else
    {
    final String firstPart = desc.substring( 0,
    dotPlace );
    final boolean firstIsClass =
    firstPart.length() <= 0 ||
    Character.isUpperCase(
    firstPart.charAt( 0 ) );
    final String secondPart = desc.substring( dotPlace
    + 1 );
    final boolean secondIsClass =
    secondPart.length() <= 0 ||
    Character.isUpperCase(
    secondPart.charAt( 0 ) );
    // don't insert words class and methods, since
    obvious from dot.
    decoratedDesc =
    "<span class=\""
    + ( firstIsClass ? "jclass" : "jmethod" )
    + "\">"
    + firstPart
    + "</span>.<span class=\""
    + ( secondIsClass ? "jclass" : "jmethod" )
    + "\">"
    + secondPart
    + "</span>";
    }
    javase6 = true;
    localOld = true;
    localRecent = true;
    longDesc = "Sun's Javadoc on " + decoratedDesc;
    }

    else if ( refWithSlashes.startsWith( "docs/codeconv" ) )
    {
    javase6 = false;
    localRecent = false;
    localOld = false;
    longDesc = "Sun's Coding Conventions on " + boldDesc;
    }
    else if ( refWithSlashes.startsWith( "docs/jdk" ) )
    {
    javase6 = true;
    localRecent = true;
    localOld = false;
    longDesc = "Sun's JDK Guide to " + boldDesc;
    }
    else if ( refWithSlashes.startsWith( "docs/jre" ) )
    {
    javase6 = true;
    localOld = true;
    localRecent = false;
    longDesc = "Sun's JRE Guide to " + boldDesc;
    }
    else if ( refWithSlashes.startsWith( "docs/legal" ) )
    {
    javase6 = true;
    localOld = false;
    localRecent = true;

    longDesc = "Sun's Legal Guide to " + boldDesc;
    }
    else if ( refWithSlashes.startsWith( "docs/platform" ) )
    {
    javase6 = true;
    localOld = false;
    localRecent = true;
    longDesc = "Sun's JDK Platform Guide to " + boldDesc;
    }
    else if ( refWithSlashes.startsWith( "docs/technotes/" ) )
    {
    if ( refWithSlashes.startsWith(
    "docs/technotes/guides/" ) )
    {
    javase6 = true;
    localOld = false;
    localRecent = true;
    longDesc = "Sun's JDK Guide to " + boldDesc;
    }
    else if ( refWithSlashes.startsWith(
    "docs/technotes/tools/" ) )
    {
    javase6 = true;
    localOld = false;
    localRecent = true;
    if ( desc.endsWith( ".exe" ) )
    {
    longDesc =
    "Sun's JDK Tool Guide to <span
    class=\"exe\">"
    + desc
    + "</span>";
    }
    else
    {
    longDesc = "Sun's JDK Tool Guide to " +
    boldDesc;
    }
    }
    else
    {
    /** css, samples */
    javase6 = true;
    localOld = false;
    localRecent = true;
    longDesc = "Sun's JDK Technotes on " + boldDesc;
    }
    }// end technotes

    else if ( refWithSlashes.startsWith( "docs/index.html" ) )
    {
    javase6 = true;
    localOld = true;
    localRecent = true;
    longDesc = boldDesc;
    }
    else
    {
    throw new IllegalArgumentException( "Sun macro bad
    reference "
    + refWithSlashes
    );
    }
    }// end docs

    else if ( refWithSlashes.startsWith( "guide/" ) )
    {
    // not same as technotes/guides
    javase6 = false;
    localOld = false;
    localRecent = false;
    longDesc = "Sun's Guide to " + boldDesc;
    }

    else if ( refWithSlashes.startsWith( "products/" ) )
    {
    javase6 = false;
    localOld = false;
    localRecent = false;
    longDesc = "Sun's Product Info on " + boldDesc;
    }
    else if ( refWithSlashes.startsWith( "webnotes/" ) )
    {
    javase6 = true;
    localOld = false;
    localRecent = false;
    longDesc = "Sun's Release notes on " + boldDesc;
    }
    else
    {
    // eg. j2ee
    javase6 = false;
    localOld = false;
    localRecent = false;
    longDesc = "Sun's documentation on " + boldDesc;
    }
    return buildSunLinks( refWithSlashes,
    localRecent,
    longDesc,
    javase6,
    localOld,
    fileBeingProcessed );
    }

    extracting the giant If does not really make the code all that
    clearer. Somehow breaking up the giant if should be higher priority.
    --
    Roedy Green Canadian Mind Products
    The Java Glossary
    http://mindprod.com
     
    Roedy Green, Aug 7, 2007
    #9
  10. On Aug 7, 1:48 pm, Roedy Green <>
    wrote:
    > On Mon, 06 Aug 2007 22:03:10 -0000, andrewmcdonagh
    > <> wrote, quoted or indirectly quoted someone
    > who said :
    >
    > >Feel free to post your original method if you'd like me to show you
    > >what I mean using your code.

    >
    > Here is the code I am trying to tidy up. Of course my mind goes blank
    > on all the other code I either tidied or attempted to tidy with a
    > similar "multiple outputs" problem.
    >
    >


    snippetty snip

    > extracting the giant If does not really make the code all that
    > clearer. Somehow breaking up the giant if should be higher priority.
    > --
    > Roedy Green Canadian Mind Products
    > The Java Glossaryhttp://mindprod.com


    Hi,

    I'm at work at present so will look at refactoring it later in the
    day, but for now, I'd can quess where I'd start.

    You are right about the big IF statement and cleanign it up. Its
    certainly one of the first I'd look at.

    I'd start by removing the duplication: E.g. setting of the 3 booleans
    to various values, possibly replacing them with an enum, or moving the
    logic and the thre booleans into its own class - thereby hiding the 3
    booleans from the world, or even using polymorhpism to remove the need
    for conditional checking at all.

    However, when I'm confronted by code like this, I tend to look at it
    from the view point of 'There's hidden classes within this method,
    never mind hidden private methods'.

    Hth

    Andrew
     
    andrewmcdonagh, Aug 7, 2007
    #10
  11. Roedy Green

    Roedy Green Guest

    On Tue, 07 Aug 2007 13:24:54 -0000, andrewmcdonagh
    <> wrote, quoted or indirectly quoted someone
    who said :

    >However, when I'm confronted by code like this, I tend to look at it
    >from the view point of 'There's hidden classes within this method,
    >never mind hidden private methods'.


    This kind of code sneaks up on you. The IF started out tiny, and
    incrementally grew. Before long you have a giant mess and you are
    wondering "What was I thinking" when I composed that monster.

    Much of it could be a big table, a list of strings and the
    corresponding classification values, with some custom code on some of
    the cases. That might be implemented as an enum, where the cases
    each have in the constructor have some booleans, and sometimes an
    overridden method or two.

    Then you can return an enum from the classifying method.

    The key is, I would like to be able to add cases or modify the logic
    without disturbing a fragile giant nested if.
    --
    Roedy Green Canadian Mind Products
    The Java Glossary
    http://mindprod.com
     
    Roedy Green, Aug 7, 2007
    #11
  12. Roedy Green wrote:
    > On Mon, 06 Aug 2007 22:03:10 -0000, andrewmcdonagh
    > <> wrote, quoted or indirectly quoted someone
    > who said :
    >
    >> Feel free to post your original method if you'd like me to show you
    >> what I mean using your code.

    >
    > Here is the code I am trying to tidy up. Of course my mind goes blank
    > on all the other code I either tidied or attempted to tidy with a
    > similar "multiple outputs" problem.

    ....
    > else if ( refWithSlashes.startsWith( "guide/" ) )
    > {
    > // not same as technotes/guides
    > javase6 = false;
    > localOld = false;
    > localRecent = false;
    > longDesc = "Sun's Guide to " + boldDesc;
    > }
    >
    > else if ( refWithSlashes.startsWith( "products/" ) )
    > {
    > javase6 = false;
    > localOld = false;
    > localRecent = false;
    > longDesc = "Sun's Product Info on " + boldDesc;
    > }
    > else if ( refWithSlashes.startsWith( "webnotes/" ) )
    > {
    > javase6 = true;
    > localOld = false;
    > localRecent = false;
    > longDesc = "Sun's Release notes on " + boldDesc;
    > }
    > else
    > {
    > // eg. j2ee
    > javase6 = false;
    > localOld = false;
    > localRecent = false;
    > longDesc = "Sun's documentation on " + boldDesc;
    > }
    > return buildSunLinks( refWithSlashes,
    > localRecent,
    > longDesc,
    > javase6,
    > localOld,
    > fileBeingProcessed );
    > }
    >
    > extracting the giant If does not really make the code all that
    > clearer. Somehow breaking up the giant if should be higher priority.


    Roedy, can't you hear the three flags and longDesc yelling at the top of
    the lungs they don't have "We're a class! We're a class!"?

    If I were refactoring that code, I would probably end up with an
    interface, two or three implementing classes for the interface, and
    another class for the flags and description. Possibly, the flags would
    turn into an EnumSet.

    The aim would be a loop something like the following:

    for(DescAnalyzer analyzer : someArray){
    if(analyzer.matches(refWithSlashes)){
    return analyzer.getResults(refWithSlashes, desc, bolddesc,//other
    parameters);
    }
    }

    where someArray contains things like:
    new ReMatcher("^products/",
    false, false, false, "Sun's Product Info on ")

    I'm not sure of all the details, and obviously have not worked out
    identifiers, but I'm reasonably sure your big If should be a table
    and a loop, and that a more relaxed attitude to creating new classes
    would get you there.

    Patricia
     
    Patricia Shanahan, Aug 7, 2007
    #12
  13. Roedy Green

    Twisted Guest

    On Aug 7, 10:22 am, Patricia Shanahan <> wrote:
    > I'm not sure of all the details, and obviously have not worked out
    > identifiers, but I'm reasonably sure your big If should be a table
    > and a loop, and that a more relaxed attitude to creating new classes
    > would get you there.


    It helps to be using an IDE. Having to put all public non-nested
    classes in separate source files and not being permitted to put whole
    piles of related, public non-nested classes into a single file may
    have its reasons, but it also makes anyone coding in Java with a plain
    text editor eschew creating new classes unless absolutely necessary,
    as they tend to have problems scaling above about ten classes in a
    project -- ten tabs/MDI windows is about the max concurrently open
    without usability problems, and 4-10 tends to be the limit on file-
    open MRU lists. More than ten classes and enough flipping back and
    forth results in frequently having to use plain file-open and navigate
    a deeply nested directory tree, which is SLOW.

    Good modern IDEs OTOH provide a project-structure tree in a navigation
    pane at the left that you can use to rapidly navigate to classes.
    Equivalent to a super-MRU-list with potentially dozens of items and
    the ability to fold parts of it up when unneded, or to having a
    modeless file-open dialog with a directory tree view perpetually open
    only taking up less screen real-estate, or suchlike.

    Eclipse comes highly recommended, of course.
     
    Twisted, Aug 7, 2007
    #13
  14. Roedy Green

    Joe Attardi Guest

    Twisted wrote:
    > Eclipse comes highly recommended, of course.

    Finally, a point that you and I agree on. Eclipse for the win!


    --
    Joe Attardi
     
    Joe Attardi, Aug 7, 2007
    #14
  15. Roedy Green

    RVince Guest

    On Aug 6, 4:19 pm, Roedy Green <>
    wrote:
    << It seems such a production to wrap three booleans as if for
    transport
    to Africa in their own class >>

    Funniest thing I;ve read in a while! While this only works for
    returning a bunch-o-booleans, and it may be more trouble than the
    Africa pack/unpack, why not just return an int representing powers of
    2? Sort a like:

    int callMyFunction(){...}

    boolean b3,b2,b1; //assume these are all initialised tofalse

    int x = callMyFunction();

    if(x>4){
    b3=true;
    x-=4;
    }
    if(x>2){
    b2=true;
    x-=2;
    }
    if(x>0){
    b1=true;
    }

    -R. Vince
     
    RVince, Aug 7, 2007
    #15
  16. Roedy Green

    Roedy Green Guest

    On Tue, 07 Aug 2007 12:48:26 GMT, Roedy Green <> wrote, quoted or indirectly quoted someone who said :

    >Here is the code I am trying to tidy up. Of course my mind goes blank
    >on all the other code I either tidied or attempted to tidy with a
    >similar "multiple outputs" problem.


    Here is how I refactored it, using an enum whimsically called SunSpot.
    The code is much longer, and somewhat slower since it does a linear search
    rather than a nested search, however it is definitely easier to maintain,
    much easier to add an alias, and easier to proofread.

    The nice thing is everything about a given SunSpot is all in one place.
    Previously the aliases were handled separately from the main logic.

    the Enum constant acts like a carrier for the three booleans.

    package com.mindprod.htmlmacros;

    import com.mindprod.common11.StringTools;
    import static com.mindprod.htmlmacros.SunJDKandJREVersions.*;

    import java.io.File;

    /**
    * Generate a reference to Sun documentation both on-line and on local hard
    * disk.
    *
    * @author Roedy Green
    * @noinspection WeakerAccess,UnusedDeclaration,WeakerAccess
    */
    public final class Sun implements Macro {

    // -------------------------- PUBLIC STATIC METHODS --------------------------
    /**
    * guts to Generate reference to a Sun HTML document.
    *
    * @param fileBeingProcessed File being processed that contains the macro to
    * be expanded.
    * @param desc human descriptinon of what it is.
    * @param ref reference e.g api/java/awt/package-summary.html
    * /s or \s. Generates http://java.sun.com/j2se/1.6.0/docs/api/java/awt/package-summary.html
    *
    * @return expand href both to on-line and local.
    *
    * @noinspection WeakerAccess
    */
    public static String expand( File fileBeingProcessed,
    String desc,
    String ref )
    {
    /* chop lead / if any */
    char firstChar = ref.charAt( 0 );
    if ( firstChar == '/' || firstChar == File.separatorChar )
    {
    ref = ref.substring( 1 );
    }
    /** reference with / instead of File.separatorChar .
    * partial or complete url.
    */
    String refWithSlashes = ref.replace( File.separatorChar, '/' );
    // find matching enum for this spot on Sun's site.
    SunSpot sunSpot = SunSpot.valueOfAlias( refWithSlashes );
    if ( sunSpot == null )
    {
    throw new IllegalArgumentException(
    " unregonised spot on Sun's site specified in Sun macro "
    + refWithSlashes );
    }
    return buildSunLinks( sunSpot.isJavase6(),
    sunSpot.isLocalRecent(),
    sunSpot.isLocalOld(),
    sunSpot.canonicalMatch( refWithSlashes ),
    sunSpot.elaborate( desc ),
    fileBeingProcessed );
    }

    // -------------------------- PUBLIC INSTANCE METHODS --------------------------
    /**
    * typical use: &lt;!-- macro Sun "JButton" api/javax/swing/JButton.html
    * --&gt; <br> see sample at mindprod/jgloss/applet.html Generate a
    * reference to a Sun HTML document
    *
    * @param parms first is description, second the reference
    * api/java/awt/package-summary.html Can use
    * either /s or \s in the url. Generates
    * http://java.sun.com/javase/package-summary.html
    * @param fileBeingProcessed File being processed that contains the macro to
    * be expanded.
    * @param quiet true if want progress messages suppressed
    *
    * @return expanded macro HTML
    */
    public final String expand( String[] parms,
    File fileBeingProcessed,
    boolean quiet )
    {
    if ( !quiet )
    {
    System.out.print( "S" );
    }
    if ( parms.length != 2 )
    {
    throw new IllegalArgumentException(
    "Sun needs description reference." );
    }
    String desc = parms[ 0 ];
    String ref = parms[ 1 ];
    return expand( fileBeingProcessed, desc, ref );
    }

    // -------------------------- STATIC METHODS --------------------------
    /**
    * Build HTML to describe the J: drive links.
    *
    * @param fileBeingProcessed File where the macro is being expanded.
    *
    * @return generated HTML
    */
    private static String buildJDriveDescription( File fileBeingProcessed )
    {
    StringBuilder sb = new StringBuilder( 200 );
    sb.append( "on your local <a class=\"plain\" href=\"" );
    sb.append( Tools.linkWithSlashes( fileBeingProcessed,
    "jgloss/jdrive.html" ) );
    sb.append( "\">J: drive</a>." );
    return sb.toString();
    }

    /**
    * Build HTML for link to Sun website.
    *
    * @param javase6 true if this is a link in the javase/6/directory
    * @param refWithSlashes reference with / instead of File.separatorChar.
    * partial or complete url.
    * @param elaborateDesc human-readable description for the link.
    *
    * @return generated HTML
    */
    private static String buildLinkToSun( boolean javase6,
    String refWithSlashes,
    String elaborateDesc )
    {
    // not localRecent, just ref to Sun site.
    StringBuilder sb = new StringBuilder( 200 );
    sb.append( "<a class=\"offsite\" href=\"http://java.sun.com/" );
    if ( javase6 )
    {
    sb.append( "javase/6/" );
    }
    sb.append( refWithSlashes );
    sb.append( "\">" );
    sb.append( elaborateDesc );
    sb.append( "</a>" );
    return sb.toString();
    }

    /**
    * Build HTML for link to JavaDoc in the current JDK.
    *
    * @param refWithSlashes reference with / instead of File.separatorChar .
    * partial or complete url.
    *
    * @return generated HTML
    */
    private static String buildLocalLinkToCurrentJDK( String refWithSlashes )
    {
    StringBuilder sb = new StringBuilder( 200 );
    sb.append( "<a href=\"" );
    sb.append( JDK_URL );
    sb.append( "/" );
    sb.append( refWithSlashes );
    sb.append( "\">" );
    sb.append( "in the JDK " );
    sb.append( JDK_FULL_VERSION );
    sb.append( "</a> " );
    return sb.toString();
    }

    /**
    * Build HTML for link to JavaDoc in the two older JDKs.
    *
    * @param refWithSlashes reference with / instead of File.separatorChar.
    * partial or complete url.
    *
    * @return generated HTML
    */
    private static String buildLocalLinkToOldJDKs( String refWithSlashes )
    {
    StringBuilder sb = new StringBuilder( 200 );
    sb.append( "or in the older <a href=\"" );
    sb.append( OLD_JDK_URL );
    sb.append( "/" );
    sb.append( refWithSlashes );
    sb.append( "\">JDK " );
    sb.append( OLD_JDK_FULL_VERSION );
    sb.append( "</a> " );
    sb.append( "or the even older <a href=\"" );
    sb.append( ANCIENT_JDK_URL );
    sb.append( "/" );
    sb.append( refWithSlashes );
    sb.append( "\">JDK " );
    sb.append( ANCIENT_JDK_FULL_VERSION );
    sb.append( "</a> " );
    return sb.toString();
    }

    /**
    * Build HTML to for links to Sun remote and local.
    *
    * @param javase6 true = on Sun's site this is a reference to the
    * javase/6/ directory.
    * @param localRecent true = docs also locally available is the JDK
    * docs.
    * @param localOld true = docs available in old locally available
    * JDK docs.
    * @param refWithSlashes reference with / instead of File.separatorChar.
    * partial or complete url.
    * @param elaborateDesc expanded human-readable description for the
    * link.
    * @param fileBeingProcessed File where the macro is being expanded.
    *
    * @return generated HTML
    */
    private static String buildSunLinks( boolean javase6,
    boolean localRecent,
    boolean localOld,
    String refWithSlashes,
    String elaborateDesc,
    File fileBeingProcessed )
    {
    refWithSlashes = Tools.armourSpaces( refWithSlashes );
    // now we have the data we need, we can build the HTML
    StringBuilder sb = new StringBuilder( 400 );
    sb.append( "\n" );
    sb.append( "<div class=\"sun\">" );
    if ( localRecent )
    {
    sb.append( elaborateDesc );
    sb.append( " : available:" );
    sb.append( "<ul>\n" );
    sb.append( "<li>\n" );
    sb.append( buildLinkToSun( javase6,
    refWithSlashes,
    "on the web at java.Sun.com" ) );
    sb.append( "</li>\n" );
    sb.append( "<li>\n" );
    sb.append( buildLocalLinkToCurrentJDK( refWithSlashes ) );
    if ( localOld )
    {
    // jre, platform and technotes might not exist in older versions.
    // Reorganised too much to automate conversion to old URL
    sb.append( buildLocalLinkToOldJDKs( refWithSlashes ) );
    }
    sb.append( buildJDriveDescription( fileBeingProcessed ) );
    sb.append( "</li>\n" );
    sb.append( "</ul>\n" );
    }
    else
    {
    // just a single link to sun without any additional wording.
    sb.append( buildLinkToSun( javase6,
    refWithSlashes,
    elaborateDesc ) );
    }
    sb.append( "</div>\n" );
    return sb.toString();
    }

    // -------------------------- INNER CLASSES --------------------------
    /**
    * enum used by Sun to encode spots on Sun's site we link to, and how they
    * are handled. Nested in Sun class.
    */
    @SuppressWarnings ( {"EnumeratedClassNamingConvention"} )
    enum SunSpot {

    TRAINING( false, false, false, "developer/onlineTraining/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Developer On-line Training on " + bold(
    desc );
    }
    },
    TECHNICAL( false, false, false, "developer/technicalArticles/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Developer Technical Articles on " + bold(
    desc );
    }
    },
    /**
    * put at end, since it is a catch all in case no more specific technote
    * category matches.
    */
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    DEVELOPER_DEFAULT( false, false, false, "developer/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Developer Documentation on "
    + bold( desc );
    }
    },
    CODECONV( false,
    false,
    false,
    "docs/books/codeconv/",
    "books/codeconv/",
    "docs/codeconv/",
    "codeconv/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Coding Conventions: " + bold( desc );
    }
    },
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    JLS( false, false, false, "docs/books/jls/third_edition/html/", "jls/" )
    {
    String elaborate( String desc )
    {
    return "Sun's JLS (<b>J</b>ava <b>L</b>anguage <b>S</b>pecification): "
    + bold( desc );
    }
    },
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    JNI( false, false, false, "docs/books/jni/", "books/jni/", "jni/" )
    {
    String elaborate( String desc )
    {
    return "Sun's JNI (<b>J</b>ave <b>N</b>anive <b>I</b>nterface) Specification: "
    + bold( desc );
    }
    },
    TUTORIAL( false,
    false,
    false,
    "docs/books/tutorial/",
    "books/tutorial/",
    "tutorial/" )
    {
    String elaborate( String desc )
    {
    return "Sun's tutorial on " + bold( desc );
    }
    },
    VMSPEC( false,
    false,
    false,
    "docs/books/vmspec/",
    "books/vmspec/",
    "vmspec/" )
    {
    String elaborate( String desc )
    {
    return "Sun's VM (<b>V</b>irtual <b>M</b>achine) Specification: "
    + bold( desc );
    }
    },
    /**
    * put at end, since it is a catch all in case no more specific book
    * category matches.
    */
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    BOOKS_DEFAULT( false, false, false, "docs/books/", "books/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Book on " + bold( desc );
    }
    },
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    API( true, true, true, "docs/api/", "api/" )
    {
    String elaborate( String desc )
    {
    // strip any leading the and trailing class
    desc = StringTools.removeHead( desc, "the " );
    desc = StringTools.removeTail( desc, " class" );
    // apply styles to class/method name
    final int dotPlace = desc.indexOf( '.' );
    final String decoratedDesc;
    if ( dotPlace < 0 )
    {
    decoratedDesc =
    "the <span class=\"jclass\">"
    + desc
    + "</span> class";
    }
    else
    {
    final String firstPart =
    desc.substring( 0, dotPlace );
    final boolean firstIsClass =
    firstPart.length() <= 0
    || Character.isUpperCase( firstPart.charAt(
    0 ) );
    final String secondPart =
    desc.substring( dotPlace + 1 );
    final boolean secondIsClass =
    secondPart.length() <= 0
    || Character.isUpperCase( secondPart.charAt(
    0 ) );
    // don't insert words class and methods, since obvious from dot.
    decoratedDesc =
    "<span class=\""
    + ( firstIsClass ? "jclass" : "jmethod" )
    + "\">"
    + firstPart
    + "</span>.<span class=\""
    + ( secondIsClass ? "jclass" : "jmethod" )
    + "\">"
    + secondPart
    + "</span>";
    }
    return "Sun's Javadoc on " + decoratedDesc;
    }
    },
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    JDK( true, true, false, "docs/jdk/", "jdk/" )
    {
    String elaborate( String desc )
    {
    return "Sun's JDK Guide to " + bold( desc );
    }
    },
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    JRE( true, true, false, "docs/jre/", "jre/" )
    {
    String elaborate( String desc )
    {
    return "Sun's JRE Guide to " + bold( desc );
    }
    },
    LEGAL( true, false, true, "docs/legal/", "legal/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Legal Guide to " + bold( desc );
    }
    },
    PLATFORM( true, false, true, "docs/platform/", "platform/" )
    {
    String elaborate( String desc )
    {
    return "Sun's JDK Platform Guide to " + bold( desc );
    }
    },
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    TECHNOTE_GUIDES( true,
    false,
    true,
    "docs/technotes/guides/",
    "technotes/guides/" )
    {
    String elaborate( String desc )
    {
    return "Sun's JDK Technote Guide on " + bold( desc );
    }
    },
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    TECHNOTE_TOOLS( true,
    false,
    true,
    "docs/technotes/tools/",
    "technotes/tools/",
    "tools/" )
    {
    String elaborate( String desc )
    {
    if ( desc.endsWith( ".exe" ) )
    {
    return "Sun's JDK Tool Guide to <span class=\"exe\">"
    + desc
    + "</span>";
    }
    else
    {
    return "Sun's JDK Tool Guide to " + bold( desc );
    }
    }
    },
    /**
    * put at end, since it is a catch all in case no more specific technote
    * category matches.
    */
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    TECHNOTE_DEFAULT( true, false, true, "docs/technotes/", "technotes/" )
    {
    String elaborate( String desc )
    {
    return "Sun's JDK Technotes on " + bold( desc );
    }
    },
    /**
    * put at end, since it is a catch all in case no more category
    * matches.
    */
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    DOCS_DEFAULT( false, false, false, "docs/" )
    {
    String elaborate( String desc )
    {
    return "Sun's documentation on " + bold( desc );
    }
    },
    GUIDE( false, false, false, "guide/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Guide to " + bold( desc );
    }
    },
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    J2EE( false, false, false, "j2ee/" )
    {
    String elaborate( String desc )
    {
    return "Sun's J2EE docs on " + bold( desc );
    }
    },
    JAVADOC( false, false, false, "j2se/javadoc/" )
    {
    String elaborate( String desc )
    {
    return "Sun's JavaDoc documentation on " + bold( desc );
    }
    },
    PERFORMANCE( false, false, false, "performance/jvmstat" )
    {
    String elaborate( String desc )
    {
    return "Sun's Performance documentation on " + bold(
    desc );
    }
    },
    PRODUCTS( false, false, false, "products/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Product Info on " + bold( desc );
    }
    },
    WEBNOTES( true, false, false, "webnotes/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Release notes on " + bold( desc );
    }
    },
    WEBSERVICES( false, false, false, "webservices/" )
    {
    String elaborate( String desc )
    {
    return "Sun's Glassfish community webservice: " + bold(
    desc );
    }
    },
    /**
    * put at end, since it is a catch all in case no more category
    * matches.
    */
    @SuppressWarnings ( {"EnumeratedConstantNamingConvention"} )
    GENERAL_DEFAULT( false, false, false, "" )
    {
    String elaborate( String desc )
    {
    return "Sun's documentation on " + bold( desc );
    }
    };

    /**
    * constructor
    *
    * @param javase6 true on Sun's site is this a reference to the
    * http://java.sun.com/javase/6/ directory. False,
    * implies http://java.sun.com/
    * @param localOld Are the docs available in old locally available
    * JDK docs?
    * @param localRecent Are the docs also locally available in the
    * recent JDK docs?
    * @param startsWith string URL in macro starts with that indentifies
    * it.
    * @param altStartsWith variable length list of aliases for startsWith.
    */
    SunSpot( boolean javase6,
    boolean localOld,
    boolean localRecent,
    String startsWith,
    String... altStartsWith )
    {
    this.javase6 = javase6;
    this.localOld = localOld;
    this.localRecent = localRecent;
    assert startsWith.endsWith( "/" )
    || startsWith.length()
    == 0 : "missing trailing / on canonicalStartsWith";
    this.canonicalStartsWith = startsWith;
    assert altStartsWith.length < 1
    || altStartsWith[ 0 ].endsWith( "/" ) : "missing / on altStartsWith[0]";
    assert altStartsWith.length < 2
    || altStartsWith[ 1 ].endsWith( "/" ) : "missing / on altStartsWith[1]";
    this.altStartsWith = altStartsWith;
    }

    /**
    * @param url url from the macro command line.
    *
    * @return corected url if match, null if no match.
    */
    private String canonicalMatch( String url )
    {
    if ( url.startsWith( canonicalStartsWith ) )
    {
    return url;
    }
    for ( String alt : altStartsWith )
    {
    if ( url.startsWith( alt ) )
    {
    // replace alternate head with canonical one.
    return canonicalStartsWith + url.substring( alt.length() );
    }
    }
    return null;
    }

    /**
    * Find matching enum constant that matches either the
    * canonicalStartsWith or an alias.
    *
    * @param url url from the macro command line.
    *
    * @return matching enum constant, GENERAL_DEFAULT if no specific
    * match.
    */
    static SunSpot valueOfAlias( String url )
    {
    for ( SunSpot sunSpot : SunSpot.values() )
    {
    String canonicalUrl = sunSpot.canonicalMatch( url );
    if ( canonicalUrl != null )
    {
    return sunSpot;
    }
    }
    return GENERAL_DEFAULT;
    }

    /**
    * get decorated long version of the description to display
    *
    * @param desc description from the macro line
    *
    * @return expanded long verion of the description.
    */
    abstract String elaborate( String desc );

    /**
    * what the URL specified in the macro starts with. This is the official
    * prefix for URLs pointing to this spot on Sun's site.
    */
    private final String canonicalStartsWith;

    /**
    * aliases canonicalStartsWith strings.
    */
    private final String[] altStartsWith;

    /**
    * get bold version of description.
    *
    * @param desc description of this link.
    *
    * @return bold version of description.
    */
    private static String bold( String desc )
    {
    return "<b>" + desc + "</b>";
    }

    /**
    * Are the docs also locally available in the recent JDK docs?
    */
    private final boolean localRecent;

    /**
    * Are the docs available in old locally available JDK docs?
    */
    private final boolean localOld;

    /**
    * true on Sun's site is this a reference to the http://java.sun.com/javase/6/
    * directory. False, implies http://java.sun.com/
    */
    private final boolean javase6;

    /**
    * Are the docs also locally available in the recent JDK docs?
    *
    * @return true if available in local recent JDK.
    */
    boolean isLocalRecent()
    {
    return localRecent;
    }

    /**
    * Are the docs also locally available in the old JDK docs?
    *
    * @return true if available in local old JDK.
    */
    boolean isLocalOld()
    {
    return localOld;
    }

    /**
    * Is this is javase/6 dir?
    *
    * @return true on Sun's site is this a reference to the
    * http://java.sun.com/javase/6/ directory. False, implies
    * http://java.sun.com/
    */
    boolean isJavase6()
    {
    return javase6;
    }
    }// end SunSpon enum
    }// end Sun
    --
    Roedy Green Canadian Mind Products
    The Java Glossary
    http://mindprod.com
     
    Roedy Green, Aug 7, 2007
    #16
  17. Roedy Green

    Lew Guest

    Joe Attardi wrote:
    > Eclipse for the win!


    Or NetBeans!

    --
    Lew
     
    Lew, Aug 7, 2007
    #17
  18. RVince wrote:
    > int callMyFunction(){...}
    >
    > boolean b3,b2,b1; //assume these are all initialised tofalse
    >
    > int x = callMyFunction();
    >
    > if(x>4){
    > b3=true;
    > x-=4;
    > }
    > if(x>2){
    > b2=true;
    > x-=2;
    > }
    > if(x>0){
    > b1=true;
    > }


    b1 = x & 1;
    b2 = x & 2;
    b3 = x & 4;

    is, IMHO, easier to understand (and debug). You also don't need
    predeclarations to false.
    --
    Beware of bugs in the above code; I have only proved it correct, not
    tried it. -- Donald E. Knuth
     
    Joshua Cranmer, Aug 7, 2007
    #18
  19. Roedy Green

    Wojtek Guest

    RVince wrote :
    > On Aug 6, 4:19 pm, Roedy Green <>
    > wrote:
    > << It seems such a production to wrap three booleans as if for
    > transport
    > to Africa in their own class >>
    >
    > Funniest thing I;ve read in a while! While this only works for
    > returning a bunch-o-booleans, and it may be more trouble than the
    > Africa pack/unpack, why not just return an int representing powers of
    > 2? Sort a like:
    >
    > int callMyFunction(){...}
    >
    > boolean b3,b2,b1; //assume these are all initialised tofalse
    >
    > int x = callMyFunction();
    >
    > if(x>4){
    > b3=true;
    > x-=4;
    > }
    > if(x>2){
    > b2=true;
    > x-=2;
    > }
    > if(x>0){
    > b1=true;
    > }


    None of this makes me the least bit happy (pun intended!).

    By creating some arbitrary way of storing information you are creating
    a potential for problems down the road. Either in adding new boolean
    returns or trying to understand your own code.

    There is nothing wrong with simply creating a class or private nested
    class to hold this information, then passing it back. The method naming
    removes all ambiguity, and moreover using a class allows the future
    addition of other return values.

    Any savings in initial coding time will be eaten up by later trying to
    figure things out (extensive, comprehensive, complete, and UPDATED
    comments not withstanding).

    I always try to code with future maintenance in mind. I have been
    bitten too many times by my own "clever" code.

    --
    Wojtek :)
     
    Wojtek, Aug 7, 2007
    #19
  20. Roedy Green

    Eric Sosman Guest

    Joshua Cranmer wrote On 08/07/07 17:03,:
    > RVince wrote:
    >
    >>int callMyFunction(){...}
    >>
    >>boolean b3,b2,b1; //assume these are all initialised tofalse
    >>
    >>int x = callMyFunction();

    >
    > >
    > > if(x>4){
    > > b3=true;
    > > x-=4;
    > > }
    > > if(x>2){
    > > b2=true;
    > > x-=2;
    > > }
    > > if(x>0){
    > > b1=true;
    > > }

    >
    > b1 = x & 1;
    > b2 = x & 2;
    > b3 = x & 4;
    >
    > is, IMHO, easier to understand (and debug). You also don't need
    > predeclarations to false.


    There is, however, one tiny drawback: javac rejects
    the code. A possible remedy:

    b1 = (x & 1) != 0;
    b2 = (x & 2) != 0;
    b3 = (x & 4) != 0;

    --
     
    Eric Sosman, Aug 7, 2007
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Refactorit

    come learn all about refactoring

    Refactorit, Feb 22, 2004, in forum: Java
    Replies:
    0
    Views:
    347
    Refactorit
    Feb 22, 2004
  2. Sebastian Jekutsch

    Survey on refactoring activities using IDEs

    Sebastian Jekutsch, Jun 8, 2004, in forum: Java
    Replies:
    5
    Views:
    479
  3. Christian Bongiorno

    Odd Multi-thread behavior when refactoring

    Christian Bongiorno, Jun 21, 2004, in forum: Java
    Replies:
    1
    Views:
    394
    Thomas Weidenfeller
    Jun 22, 2004
  4. Anan H. Samiti
    Replies:
    33
    Views:
    5,539
    Roedy Green
    Jul 30, 2004
  5. -
    Replies:
    6
    Views:
    629
    Wibble
    May 14, 2005
Loading...

Share This Page