10 Replies Latest reply on Mar 12, 2015 9:13 PM by ddyer00

    can someone explain, and/or justify this?

    ddyer00

           x=app.activeDocument.viewPreferences.horizontalMeasurementUnits

           Result: PICAS

      // so far, so good.  Just to be sure...

           x.toString()

           Result: PICAS

      // now

           x+x

           Result: 4108374726

      // huh?

           x+x.toString()

          Result: 2054187363PICAS

      // and finally

          "units are "+x

          Result: units are 2054187363

       

      I suppose there's some explanation why the measurement units for picas is secretly associated

      with the integer 2054187363 and why it's a good idea.

        • 1. Re: can someone explain, and/or justify this?
          TᴀW Adobe Community Professional & MVP

          The answer is simply that MeasurementUnits is an enumerator. So really

          the fundamental value of each particular MeasurementUnit is an integer,

          as is the case for any enumerator.

           

          When you write x = myDoc.viewPreferences.horizontalMeasurementUnits,

          InDesign is actually doing you a favour in that it returns something

          comprehensible (PICAS, CM, etc.). In fact, if I recall correctly, in

          older versions (CS4), you'd only ever get the enum value.

           

          So in fact it is possible to write:

          myDoc.viewPreferences.horizontalMeasurementUnits = 2053335395 and it

          will be set to Ciceros, in this case. (All the numbers are listed in the

          OMV in ESTK).

           

          If you write:

           

          app.viewPreferences.horizontalMeasurementUnits.valueOf()

           

          You'll get the actual enumerator number.

           

          However, because Javascript is freely typed, it will helpfully convert

          something to a string if you alert() it, or display it in the Console, etc.

           

          So, as per your examples: if you add two enumerators, the interpreter

          does not do a toString(), hence you get an integer.

           

          If you add an enum to a string (as in the second example), it's like

          adding any number to a string: 5+"z" will give: 5z.

           

          In the last example, the enum remains an integer.

          • 2. Re: can someone explain, and/or justify this?
            ddyer00 Level 1

            This almost makes sense, but the behavior of the enumerator object

            is odd with respect to the + operator.  What is the point of giving an

            enum any meaning as an integer at all?

             

            for most objects,  object+object becomes object.toString()+object.toString(),

             

            so what magic causes this enumerator to be interpreted as an integer, and why is that desirable?

            • 3. Re: can someone explain, and/or justify this?
              Vamitul Level 4

              Enumerators do not call .toString() automatically. Why is that, i have no idea, but i agree it is bad, and can lead to very strange behaviour.

              Your MeasurmentUnits example is just the tip of the iceberg. Worst culprits are the SpecialCharacters enumerator and the worst of the worst: NothingEnum.NOTHING that gets returned in some cases. The big problem with NOTHING is that, when converted it gets evaluated to True, even if it is a considered a falsy value. Even "better", the same member, on different objects will sometimes return Nothing and other times will return null, for example text.appliedCharaterStyle will return null, but findTextPreferences.appliedCharacterStyle willl return NothingEnum.NOTHING

              • 4. Re: can someone explain, and/or justify this?
                TᴀW Adobe Community Professional & MVP

                That's just what an enumerator is: "An enumeration consists of a set of

                named integer constants."

                 

                It's a convenient way of referring to a number with a more memorable

                name. But the underlying value of any element in an enumerator is an

                integer.

                 

                There's nothing surprising about this.

                 

                Note that:

                 

                MeasurementUnits.INCHES === 2053729891

                 

                returns true.

                • 5. Re: can someone explain, and/or justify this?
                  ddyer00 Level 1

                  these enums are not integers, they are objects.  Somewhere in the bowels of their

                  behavior, unlike most objects, they respond to + as an integer rather than as a string.

                   

                  My guess is that adobe engineers, when they were adapting existing internals to a javascript interface,

                  found that then needed to do range checks on measurement units (ie; existing C code was something

                  like)

                    enum measurementunit { picas=1, points=2, inches=3 }

                   

                  and code existed that did things like

                   

                    if(units>points) {}

                   

                  and for whatever reason, they decided this semantics needed to be visible to the javascript binding.  It's a crappy

                  reason, but at least it's a reason.

                   

                  ---

                   

                  Final watchword on the subject - these objects are complete liars.  Try this:

                   

                  var x = MeasurementUnits.picas;

                  var y = 2054187363;

                  var z = "2054187363";

                  typeof x is object

                  typeof y is number

                  typeof z is string

                   

                  x==y  is true

                  x===y is also true !

                  x===z is also true !

                  y===z is false (as expected)

                   

                  so we've broken a basic identity - these enums are identical to many things that are not identical to each other.

                  • 6. Re: can someone explain, and/or justify this?
                    Marc Autret Level 4

                    Hi all,

                     

                    Here are additional details on Enumeration and Enumerator objects in CS5 and later:

                    http://www.indiscripts.com/post/2012/07/indesign-scripting-forum-roundup-3#hd1sb1

                     

                    @+

                    Marc

                    • 7. Re: can someone explain, and/or justify this?
                      ddyer00 Level 1

                      While this does seem to describe the behavior of MeasurementUnit.picas, it still doesn't make sense

                      that "picas" and friends should have these I'm-also-a-number behaviors that do make sense for special

                      characters.

                      • 8. Re: can someone explain, and/or justify this?
                        Marc Autret Level 4

                        > it still doesn't make sense that "picas" and friends should have these

                        > I'm-also-a-number behaviors that do make sense for special characters

                         

                        The I'm-also-a-number behavior does not actually make sense whatever the enum you consider, it's just the way those objects work.

                         

                        Note, however, that Enumerator instances do not have the cast Number (the typeof operator does return 'object'). What has been done when introducing these objects in CS5 is:

                        1. Making myEnum.valueOf() return a Number.

                        2. Overriding == and === so that myEnum can match a Number in both equal and strict-equal comparisons.

                        The reason for this, IMHO, was to preserve compatibility with previous versions (CS4 and before) where Enumerations—the collection of enums—were just pointing out to numeric values, that is, Numbers.

                         

                        Thus, a syntax like (myUnit===MeasurementUnits.INCHES), or (myUnit===2053729891), or even (MeasurementUnits.INCHES===2053729891), still works from CS4 to CS5 without breaking existing code.

                         

                        Now, about the meaning of these numbers, we know they are nothing but unique identifiers. Technically—and this is an old tradition in Adobe architecture—such identifiers are all built based on 4-character sequences.

                        In the case of measurement units, identifiers are formed using the prefix 'z' and 3 relevant letters from the unit name, usually the leading letters, e.g. 'zinc' for inches, 'zpic' for picas, and so on.

                        Then, ASCII codes of these characters are taken to build a number:

                         

                        INCHES => z i n c => 7A 69 6E 63 => 0x7A696E63 (=2053729891 in decimal)

                        PICAS => z p i c => 7A 70 69 63 => 0x7A706963 (=2054187363 in decimal)

                        etc.

                         

                        And you will check that +MeasurementUnits.INCHES is 0x7A696E63.

                         

                        Anyway, your comment #5 highlights something else, based on the code:

                         

                        var x = MeasurementUnits.picas;

                        var y = 2054187363;

                        var z = "2054187363";

                         

                        We have checked, indeed, that x===y is true (see reason 2 above).

                        But we also can check, as you mention, that x===z is true!!! Which is not CS4-backwards-compatible at all and sounds highly irrelevant since x.toString()==='PICAS'.

                         

                        I suspect that this strange case is a side effect of how the === operator has been overloaded. In my opinion, the hidden function Enumerator['==='](arg) mutely coerces the argument into a Number whatever it actually is. So the string z is simply taken as +z and that's why x===z also returns true. What Adobe should have done instead is:

                         

                        // JS pseudo code

                        Enumerator['==='] = function(arg){ return 'string'==typeof arg ? this.toString()==arg : this.valueOf()==+arg };

                         

                        …and then x===z would have been false, and x==='PICAS' would have been true ;-)

                         

                        @+

                        Marc

                        • 9. Re: can someone explain, and/or justify this?
                          TᴀW Adobe Community Professional & MVP

                          Great explanation, Marc!

                          • 10. Re: can someone explain, and/or justify this?
                            ddyer00 Level 1

                            I guess we've reached the point of exhaustion on this.  All I really wanted was, when packaging a rectangle

                            object to also display the units, I was shocked that defining the

                             

                               toString() { return("left+","+right+" "+width+"x"+height+" "+units) }

                             

                            printed a random looking number as the units.