Lingo in a Nutshell and Director in a Nutshell banner
Dot Syntax

This is a DRAFT. It has not been tech reviewed and likely contains errors. Some things may have changed between D7.0 and D7.0.2, so take my claims with a grain of salt.

Director 7 supports streamlined JavaScript-like dot notation (a.k.a. dot syntax). Dot Syntax is really quite simple. It is a shorthand notation that can be used to specify

The following pages in Director in a Nutshell address dot syntax

See also the article on dot syntax by Zac Belado of Director Online at:

(Completely by accident, Zac's article is almost a perfect complement to mine. He takes a much more conversational and tutorial approach, with numerous examples. He covers a lot of stuff I missed and vice-versa, so you should definitely read his article too).

Dot syntax is usually optional. In most cases you can use either the new syntax or the new syntax, but there are notable exceptions: (This listing is approximate and preliminary)

These links jump around the document


The following do NOT support dot syntax. You must use the old sytnax:

Known bugs in Dot Syntax

Here are some actual bugs that exist when using the dot syntax, not just unsupported uses:

The following do NOT work with the old syntax. You MUST use dot syntax:

Back to Top


Dot Syntax for Sprite and Member properties:

This is the old style notation for sprite and member properties:

  set the loc of sprite 5 = point (50, 100)

  set the directToStage of member 2 of castLib 3 = TRUE

Here is the dot syntax equivalent to the above commands:

  sprite(5).loc = point (50, 100)

  member(2, 3).directToStage = TRUE

Here is the general form for specifying properties the old notation:

   the property of member whichMember

   the property of member whichMember of castLib whichCast

   the property of sprite whichSprite

In D7, you can use the equivalent dot notation:

   member(whichMember).property

   member(whichMember, whichCast).property

   sprite(whichSprite).property

  

Note that you can cascades expressions:

In the old notation

   the property of the subObject of the object

In dot sytnax it would be:

   object.subobject.property

In the old notation, you specify the properties first and the object last. Intervening objects (in this case a rect) can be specified by adding another "of the object" clause

   put the width of the rect of the stage

In dot syntax, start with the object first, and specify the property last. Intervening objects (in this case a rect) can be specified between the dots:

   put (the stage).rect.width    

Don't confuse member properties with the member of sprite and memberNum of sprite properties, which determine a sprite's cast member (such as a bitmap) and can be changed at runtime to change a sprite's appearance.

   sprite (whichSprite).member = member(whichMember, whichCast)

   sprite (whichSprite).memberNum = the number of member(whichMember, whichCast)

See pages 134-135 of Chapter 4, CastLibs, Cast Members, and Sprites, in Director in a Nutshell for many more details on specifying a member, sprite, memberNum, castLibNum, etc.

The dot syntax equivalent of:

   put the number of member w of castlib "where"

Would be

   put member(w, "where").number

Back to Top


Accessing the properties of an object.

There are many ways to access the properties of an object. In D7, there is a new object called the globals. Try these tricks with it in the message window:

The globals is an object, not a list.

   put the globals

   -- (the globals)

This clears globals for our test:

   clearGlobals

This displays currently defined globals

   showGlobals

   -- Global Variables --

   version = "7.0.2"  -- Version is a global that can't be cleared

Here are various ways to access a global variable

   put version

   -- "7.0.2"

   put the globals.version

   -- "7.0.2"

   put the version of the globals

   -- "7.0.2"

   put the globals[#version]

   -- "7.0.2"

Assigning a variable in the message window creates a global. Here is a user-defined global variable:

   foo = 5  

   showGlobals

   -- Global Variables --

   foo = 5

   version = "7.0.2"

Again, any global can be accessed with any of these syntaxes:

   put foo

   -- 5



   put the globals.foo

   -- 5



   put the foo of the globals

   -- 5



   put the globals[#foo]

   -- 5

Note that elements in a list can be accessed using the above syntaxes as well. Lists are a type of object but not all objects are lists.

Note that these examples do not work:

   put the #foo of the globals -- Don't use the # in this syntax



   put the globals[foo]  -- You need a # in front of foo

   -- <Void>



   put the globals.#foo -- Don't use the # in this syntax

   put globals.foo -- You need the word "the" in front of "globals"



   put globals  -- "globals" is not the same as "the globals"

   -- <Void>



Back to Top


To Set or Not To Set

In some cases, you can't use set in a dot syntax expression.

This causes an error:

  set sprite(1).rotation  = 40

But this works:

  sprite(1).rotation = 40

This works:

  set y = sprite(1).rotation

  put y

  -- 40

This sets y to the "object" sprite(1)

  set y = sprite(1)

This works (note the use of the word "set", which didn't work in the earlier example)

   set y.rotation = 40

Therefore, my assumption is that following the word "set" you must have a variable name and not an object such as "sprite". This allows the compiler to assume that "y" is a variable holding a pointer to an object reference and not the object itself. This is probably an arbitrary distinction that they could have coded around, but I assume it just made the compiler that much simpler.

As a rule of thumb, don't use "set" with the new dot syntax. I don't think it is ever needed, and as you see, sometimes fails.

It may have mad it easier to write a parser if the engineer made certain assumptions about the next token. This makes development faster for the engineers, and compiling faster for the users, assuming that the users know the compilers limitation. Remember that the compiler may compile 1000's of lines of code, so a small optimization can be important. Add to this the fact that you compile frequently in Lingo because you know it is so fast and cheap to do so, as opposed to C where it is more lengthy and less frequent to build an executable.

Back to Top


Properties of Objects, and using "The"

You need to specify the "the" in front of the initial object, but not for intervening properties such as "rect" (see examples below)

Be sure to specify "the stage" as the object instead of just "stage"

  put stage.rect -- FAILS



  put the stage.rect -- Succeeds

  -- rect(96, 71, 736, 571)

Be sure that the property is a valid property for that object. There is no "width of the stage" property:

  put the stage.width -- FAILS

Specify rect.width as the property instead (which is equivalent to put the width of the rect of the stage)

  put the stage.rect.width

  -- 640

Be sure that you are specifying an object as the first item

Compare these cases:

on mouseUp me

   put sprite(me).spriteNum.loc -- This fails

end

The above example fails because the expression sprite(me).spriteNum. is an integer (in this case the sprite's number) and loc is a property of an object, not a property of an integer!

You have to rearrange the parentheses. The correct syntax is:

on mouseUp me

   put sprite(me.spriteNum).loc 

end

where sprite(me.spriteNum) evaluates to a sprite reference, such as sprite(5), from which we can extract the loc property.

Here is another example:

  y = 5

  put y.loc -- This fails

Try this instead:

  y = sprite(5)

  put y.loc -- This works

When in doubt, use the Debugger and Watcher windows to check the value of an express.

Make sure you include the word "sprite" and check that your parentheses are correct. Add parentheses as necessary. Here is a really cool line of code to create a new bitmap cast member and fill it with a screenshot of the stage.

  (new(#bitmap)).picture = (the stage).picture

Back to Top


Dot notation for Lists

D7's new bracket syntax is useful with lists. This is the old syntax:

   x = getAt (exampleList, 1)

   setAt (getAt(someList, 7), 4, "newValue")

Here is the dot syntax equivalent to the above commands:

   x = exampleList[1]

   someList[7][4] = "newValue"

You can also access properties in a list. Try this (and note that "#apple" is a symbol and requires the # character):

   x = [#apple:3]

   put x[#apple]

You can also use theses syntaxes:

   put the apple of x

or

   put x.apple

See Accessing the Properties of an Object for more details.

You can also specify a list function to perform on the list after the list name, such as:

  put x.count

See Dot Syntax for Functions below.

There is a lot more that you can do with lists and the bracket syntax that I don't cover here. Hopefully I'll add it in the future.

See Chapter 6, Lists, of Lingo in a Nutshell for a full discussion of list using the older syntax.

Back to Top


Dot Syntax for Functions

You can now specify functions at the end of an object instead of the other way around.

Old Style:

  t = "my text"

  put length(t)

  put count ([1, 2, 3, 4, 5])

New style

  put t.length

  put [1,2,3,4,5].count

Back to Top


Dot Syntax and Bracket Notation for Text and Strings

The D7 dot notation can be confusing when working with text members and strings. The count property cannot count a string, it can only count chars, items, words, lines, or paragraphs in a string. Therefore, the following fails:

  set testString = "Thanks I'll Eat Here"

  put testString.count

The following is a supported use of count (note that "char" and "word" are singular):

  put testString.char.count

  -- 20

  put member("text member").word.count

  -- 4

Bugs have been reported in D7.0 when counting lines and paragraphs using this method, especially with longer text contents. Upgrade to D7.0.2 or include the word text when using count, such as:

  put member("text member").text.line.count

  -- 69

  put member("text member").text.paragraph.count

  -- 13

You can use brackets to extract a subportion of a string. Here are some D6 style expressions:

   put word 3 of testString

  put char 3 of word 1 of testString

Note the following dot sytnax expressions use integers in brackets to specify a string chunk:

   put testString.word[3]

   -- "Eat"

   put testString.word[1].char[3]

   -- "a"

Use two dots within brackets to specify the starting and ending range of chars, words, etc., such as:

   put member("text member").word[1..2]

   -- "Thanks I'll"

Do NOT use three dots (an ellipsis) because Director will interpret that thrid dot as a decimal point, such as:

  put member("text member").word[1...2]  -- This is wrong

In the above case, the ending number is interpreted as the decimal 0.2, which is then rounded to 0. So Director interprets it as:

  put member("text member").word[1..0]

Caveats

The number and last properties don't work with dot notation. Use the old style:

   put the numbers of chars of testString

   put the last char of testString

Use the text property to extract the contents of a #text member. The following is wrong:

  put member("text member").length

  -- 0

The following is correct. Note the addition of the property "text" in the middle of the expression:

   put member("text member").text.length

   -- 21

Back to Top


The Ref keyword in Text expressions

Use the ref keyword to create a temporary object that holds a specified text chunk that can be used easily in subsequent repeated chunk operations. You first create the reference, then use it in any number of future expressions. Note the position of the keyword "ref" at the end of the initial expression:

   set temp = member("text member").word[1..2].ref

   put temp

   -- <Prop Ref 2 157b9ec>

   put temp.text

   -- "Thanks I'll"

   put temp.char[5]

  -- "k"

You can use the selectedText of member as an object that represents the current selection:

  put member("text member").selectedText.word[1]

  -- "Eat"

You can use the selection of member to return a list of the starting and ending characters within the current selection:

   put member("text member").selection

   -- [13, 15]

Properties that can be cascaded with chunk expressions (fontSize, alignment, etc.) can NOT be mixed with the D7's member(x,y) notation. The following will NOT work:

  set the font of member(2, 3) = "Geneva"

You must either use the old-style member syntax for the entire command:

  set the font of member 2 of castLib 3 = "Geneva"

or use the new-style syntax for the entire command:

  member(2,3).font = "Geneva"

Properties that apply to the entire member can use the mixed notation, such as:

  set the editable of member(2, 3) = TRUE

A bug in D7.0 prevents a fontStyle setting from taking effect if the first character in the chunk already contains the style. Upgrade to D7.0.2 or set the range to [#plain] before setting the desired style.

The html and rtf properties apply only to entire text members, not strings or chunks. This will fail:

  put member("text member").paragraph[1].html

The following will print out the first paragraph of rtf codes, not formatted text:

  put member("text member").rtf.paragraph[1]

Here are some ways to get the length of a string

   sLength = member("something").text.char.count



   sLength = member("something").text.length

And then use this to truncate the string to the first 5 characters :

   delete member("something").char[5..sLength]

Use two dots, not three in the expression char[5..sLength]

Back to Top


Text members vs. Field members Nomenclature

Dot notation does NOT work for older field cast members. The older syntax does NOT work with newer text cast members. You may need to use the old style with fields and the new style with text members.

This works for fields, but not text:

  put the fontStyle of char 1 of member 7

Fields use the following D7 dot notation:

  put member(7).fontStyle.char[1]

But text members use:

  put member(7).char[1].fontStyle

Back to Top


Menu Commands

The menu and menuItem properties do not support the D7 dot notation. (this was the case in D7.0. I'm not sure about D7.0.2). Use the older style notation:

  the property of menuItem whichItem in menu whichMenu

where whichItem is a menu item's name or number, and whichMenu is a menu's name or number, and property is a valid menuItem property (checkMark, enabled, name, or script) as described in Table 14-8 on page 477 of Director in a Nutshell.

You can also use the undocumented in ikeyword in lieu of of in the first part of the expression

the property in menuItem whichItem in menu whichMenu

Back to Top


Non-supported Uses of Dot Syntax:

Dot notation is not implemented in all cases. You can NOT do the following in dot notation.

Number of Member

The number of member won't work when specifying a castLib

The following will NOT work correctly

  put the number of member (5,2)

  -- 5 2

Use this instead

  put the number of member 5 of castLib 2

  -- 131077

Member().Number

Checking the number of member by name will generate an error in D7 if the member doesn't exist:

   if member ("nonexistent").number < 0 then alert "Oops!"

Use this instead:

   if the number of member ("nonexistent") < 0 then alert "Oops!"

If the member does exist, you can use either of these:

   put member ("exists")

   put member("exists", 5) -- where 5 is a castLibNum

Number of Members

  put castlib(1).members.number -- results in a script error

Use this instead:

  put the number of members of castLib 1

When referring to a member within a castLib, use:

  put member (memberNum, castLibNum)

such as:

  put member (27, 2)

  -- (member 27 of castLib 2)

Number of CastLibs

  put castlibs.number -- results in a script error

Use this instead:

  put the number of castLibs

Last Chunk

  myText = "A B C"

  put myText.char.last -- results in a script error

Use this instead:

  put the last char of myText

Sound Channel references

You can't reference the sound channels. via dot sytnax. The D7 Lingo Dictionary incorrectly claims that this works, but it does not:

  sound(1).volume  = 255

Use this instead:

  the volume of sound 1 = 255

Character references in assignment statements

This fails in D7.0 (I didn't test it in D7.0.2)

  inString.char[x] = numToChar(65)

Use this instead:

  put numToChar(65) into char x of instring

Environment Property

The elements in the environment property are not consistently accessible via dot syntax. Observe the following:



put the environment

-- [#shockMachine: 0, #platform: "Macintosh,PowerPC", #runMode: "Author", #colorDepth: 8]



set the colordepth of the environment = 16 -- This fails because it is not settable



put environment.colordepth -- Fails. You need the word "the"



put the environment.colordepth  -- Succeeds

-- 8



put the shockmachine of the environment -- Succeeds

-- 0



put count(the environment)  -- Succeeds

-- 4



put environment[2] -- This fails! You need the word "the"

put (the environment)[2] -- Succeeds

Back to Top


Old Syntax that will break in Director 7

The D7 Lingo compiler is NOT 100% backward compatible with prior versions. It will NOT correctly interpret some possible phrases that worked in prior versions due to new meanings associated with the syntax in the new compiler. The following two cases are both covered in the D7 ReadMe. I am not aware of other cases related to dot syntax. There is a third case, unrelated to dot syntax, of in which undeclared global variables worked in prior versions, but are now not functional.

Parentheses around member references not allowed when including a castLib number

This will no longer work in D7.

   x = 5

   y = 2

   put member(x+1) of castLib y

use this instead:

 put member x+1 of castlib y

or this:

put member(x,y)

 

Periods not allowed in variable or property names

Property names or variable names that contains periods (dots), which was most common when using a float as a property name, will no longer work.

In D6, these worked:

   set myList = [3.14: #pi]

   set myList = [#7.5: "foo"]

   set myList = [#node6.9: "cheese"]

   set node6.9 = "cheese"

In D7, it won't work. Use these instead (which may require restructuring your code)

   myList = [#pi: 3.14]

   myList = [#foo: 7.5]

   myList = [#node6_9: "cheese"]

   node6_9 = "cheese"

Use of undeclared global variables

Prior to D7, the first parameter passed to a function would be treated implicitly as a global variable. In D7, this no longer works. You should declare the global explicitly as was always good practice.

See page 61 and following of LiaN, "Special Treatment of the First Argument Passed". That discussion applies only to D6, not D7. In D6, you could use reference a global variable that had been declared elsewhere by using it thusly:

on test

   put getAt (gMyList, 5)

end

In D7, you must declare the global or oyu'll get a "Variable used before assigned a value" error:

on test

   global gMyList

   put getAt (gMyList, 5)

end

Or, more succinctly:

on test

   global gMyList

   put gMyList[5]

end

 

Back to Top


Rumors and Innuendo

 

Marabeth Grahame reported a script error in D7 movie when using this:

  set the loc of sprite 152 = point(-100, -100)

'Script error: Sprite number wrong. set the loc of sprite 152 = point(-100, -100)'

D7 allegedly wanted

  sprite(152).loc = point(-100, -100)

I surmised that the failure was only true for sprite channels above 120, assuming that there must be code in the old compiler checking for that limitation.

The allegedly problematic syntax worked for me (on D7 on a Mac) as long as specifying a sprite less than the lastChannel

  set the loc of sprite 152 = point(-100, -100)

Perhaps it is a problem only when upgrading a movie from D6, but it works fine in D7 from scratch for me.

Marabeth reported it may be related to the ubiquitous 205 errors, but the issue was never definitively resolved.

Back to Top


Performance and Optimization of Dot Syntax (The Truth about Dot Syntax)

Macromedia originally claimed that there is no speed difference between D7's new dot notation and the older syntax. I even repeated this claim on Page 290 of Director in a Nutshell. In some cases, this is misleading if not outright false.

Macromedia had stated in the past that both the old and new syntax compile down to the exact same bytecode, but that does not appear to be true in the purest sense. A dot syntax reference causes Director to instantiate an object. If possible, do this once outside of, say, a repeat loop and store the result in a variable. Then use the variable within the repeat loop.

This is slow because it repeated instantiates the sprite object each time an exitFrame command is sent.

on exitFrame me

  sprite(me.spriteNum).loc = the mouseLoc

end

Instead, instantiate the sprite object reference once in your beginSprite handler and use thusly

property pSpr



on beginSprite me

  pSpr = sprite(me.spriteNum)

end



on exitFrame me

  pSpr.loc = the mouseLoc

end

Here are some other tests you can run. Create a huge variable containing text and then count the number of characters:

Test this in a repeat loop and time how long it takes to do it 1000 times.

   t = "Some gargantuan string you'll need to create"

   startTimer

   repeat with x = 1 to 1000

      c = t.char.count

   end repeat

   put the timer

Now use the old style syntax in the loop and it should be faster:

set c = the number of chars of t

Likewise, you'll see differences with the length() function

c = t.length   -- Dot syntax is slower

c = length(t)  -- Older syntax is faster

Werner Sharp responds:

length(t) is faster than t.length, because the first case takes an object reference and uses it directly versus the second case which has to allocate an object reference for "t". (Essentially making a copy of the string.)

So when tweaking performance, be conscious of object references and try to create them once and store them in a variable.

Back to Top


Using the spriteNum of me vs. me.spriteNum vs. spriteNum alone

When a Behavior is reached, it is "instantiated" and that script instance is used to refer to that Behavior during its lifetime. The script instance is called "me" and it is passed to handlers within the Behavior automatically when Director issues an event. It is also sent when using sendSprite and sendAllSprites.

The script instance, me, has one property (called the spriteNum) by default.

Therefore me.spriteNum is the number of the sprite to which the script is attached.

Here is a sample Behavior template:

property pSpr



on beginSprite me

  pSpr = sprite(me.spriteNum)

end

Then you can add things like this in the same Behavior script

on mouseDown me

   pSpr.member = member ("new bitmap")

end



on exitFrame me

  pSpr.loc = the mouseLoc

end

If you specifically declare the spriteNum property, you don't need the to specify me.spriteNum when using spriteNum.

property spriteNum



on beginSprite me

  sprite(spriteNum).loc = point(320,240)

end

Here are some other examples of me.spriteNum in an expression

This will work (thanks to akob Hede Madsen for pointing this out) but is not the preferred method:

on exitFrame me

   (sprite me.spriteNum).loc = the mouseLoc

end

This is the preferred syntax:

on exitFrame me

  sprite(me.spriteNum).loc = the mouseLoc

end

You can use the spriteNum of me in D6 or D7, and you can use just spriteNum if you declare it as a property at the top of your Behavior, such as:

on beginSprite me

  set the loc of sprite (the spriteNum of me) = point (320, 240)

end

Or, also in D6:

property spriteNum



on beginSprite me

  set the loc of sprite (spriteNum) = point (320, 240)

end

You can only use spriteNum without the me, as shown above, if you have declared me as the first parameter to the handler. This won't work:

property spriteNum



on beginSprite  -- We're missing "me" here

  set the loc of sprite (spriteNum) = point (320, 240)

end

If something fails, be sure to declare me as the first parameter, or use the currentSpriteNum instead.

on beginSprite

  set the loc of sprite (the currentSpriteNum) = point (320, 240)

end

 

Back to Top

 



Zeus Home Page | LIAN TOC | DIAN TOC | Links | E-Mail

Place an Order | Downloads | FAQ | GuestBook | Glossary

[End of Page]

Copyright © 1996-1999. Bruce A. Epstein. All Rights Reserved.

(The page last revised September 9, 1999)