Setting 'class' property in a record fails

According to the AppleScript 2 Language Guide you can give a record a ‘class’ property, and it will override the default class of ‘record’:

set myRecord to {class:integer, min:1, max:10}
class of myRecord --> integer

Sanderson & Rosenthal use this when creating an associative list, with this structure:

set myArray to {class:"associative list", the_items:{}}

That second snippet fails on my Macs.
On Macs with 10.6.3 I get a dropdown sheet with text “AppleScript error” in bold, and below it “(null)” in small print. After a varying number of seconds AppleScript Editor crashes.
On our last 10.4 Mac it does not crash the editor, but the script never finishes running.

The first snippet works OK everywhere. I’m guessing you can have a ‘class’ property, but its value must be some other class that actually exists in A/S, not a string. When looking up ‘class’ in the ALG it says

A literal string is no such thing, I believe. Is this a typo??
Can anybody shed any light on this?

The first snippet has no quotes around integer. The second has quotes. If you remove the quotes and the “associative” part it works fine.

It’s wrong, unless they were writing in some context where it’s possible. With a record, you have to use something that AppleScript recognises as a class, even if it’s one you’ve made up yourself:

set myArray to {class:«class alst», the_items:{}}
class of myArray --> «class alst»

However, using text appears to be possible with a script object:

script myArray
	property class : "associative list"
	property the_items : {}
end script
class of myArray --> "associative list"

Trying to put myArray the record into a list causes another error on my machine, while doing the same with myArray the script object seems fine.

Yes, that’s what they’re doing further on. At this point it was just a set of handlers. I now think that the property being ‘class’ is irrelevant. You just need something that is never accessed by the handlers. You might say

set theAssociativeList to {typeClass:"associative list", the_items:{}}

Having a true ‘class’ property is cleaner, of course. I’m learning…

It looks like the class name needs to be 4 characters.
«class n[]b» is acceptable, so it’s not the same as an identifier.
Any other limitations?

I wish I had! :lol:

Yes. I believe the four characters equate to a four-byte token which can be read straight off like an integer.

It’s the token to which the identifier (keyword) would compile if there were one for that class. For example, try compiling this, which does have a keyword defined for it:

«class utxt»

Only in what you can do with the result. :slight_smile:

set myArray to {class:«class noob», the_items:{}}

set l to {}
set end of l to myArray

class of myArray --> «class noob»
-- But it's still a record:
every «class noob» of l --> {}
every record of l --> {{class:«class noob», the_items:{}}}

Well it seems like you want an object and you’re looking in the record section. A record is just a dictionary and can’t behave like an object.

set x to {class:integer}
class of x --return: integer

The example code above returns the wrong value in my opinion. Even if it hold a key class with a value it should always return the constant record. Because the class of the record remains a record no matter what values it contains. To use class definition you should also create a class and not a dictionary. A class from your record should look like:

on newRecord()
	script prototype
		property class : "myRecord"
		property min : 1
		property max : 10
	end script
	return prototype
end newRecord

set myRecord to newRecord()

doesn’t this solve all the problems?

The only reason that I can imagine why you want a class inside a record is that different records and objects are send to a handler or are mixed in a list. So in my opinion a handler can solve this problem…

on classOfObject(theObject)
	if class of theObject is record then
		set theObject to theObject & {myClass:missing value}
		if myClass of theObject = missing value then return class of theObject
		return myClass of theObject
	else
		return class of theObject
	end if
end classOfObject

classOfObject({myClass:"myRecord", min:1, max:10}) --returns: "MyRecord"
classOfObject({myClass:integer, min:1, max:10}) --returns: integer
classOfObject({min:1, max:10}) --returns: record
classOfObject("Hello World!") --returns: text

if myClass key is defined in a record it will return that value, otherwise it will return simply the class of an object

Thank you, Nigel, DJ.
You’ve made the ride on the S & R slightly less bumpy. For now.

Part of the problem is that records aren’t really “just a dictionary”. Any user defined properties are stored like a dictionary, in a list of alternating values and keys, but where classes are used, they are stored separately as class objects containing the value.

(You can see a side effect of this in AppleScriptObjC: class values just disappear when converted to NSDictionaries.)