From fc2870f7e521a04efc61b1460c8328b65f08b5a3 Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Fri, 14 Apr 2006 02:05:19 +0000 Subject: [PATCH] Moved to msoy area. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4019 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- src/as/com/threerings/README.txt | 349 ------------------------------- 1 file changed, 349 deletions(-) delete mode 100644 src/as/com/threerings/README.txt diff --git a/src/as/com/threerings/README.txt b/src/as/com/threerings/README.txt deleted file mode 100644 index 2bcd776d7..000000000 --- a/src/as/com/threerings/README.txt +++ /dev/null @@ -1,349 +0,0 @@ -This document contains a couple of notes about some design decisions -and some notes about flash that you may find useful. - -TODO ----- -- Write code that processes a dobj class in java and outputs the - corresponding class in actionscript. This is sorta fucked because - we want to exclude things not applicable to client code, not because - we're trying to save every byte in the class definition, but because - some of those methods involve whole classes we don't need on the as client. -- Write code that generates actionscript service, listener and marshaller - classes from a java Service class definition. - - -Design decisions ----------------- -- I have kept accessors named like their Java counterparts, rather - than embracing flash's property setter/getter methods (which are really - cool), but I am starting to lean the other way and may rewrite some stuff. - -- I am embracing flash's event distribution model because it saved me a bunch - of work. - -- We could use the setter methods on DObject properties to generate dobj - events, but so far I haven't gone there. - -- We need a realistic HashMap implementation. Using Object properties - (a-la my SimpleMap) is not going to cut it because keys must always - be Strings.and there's no way to *really* remove a value from - an Object (you can set the property to null, but now the property is - forever defined: the key is not cleared) - ***Update: the 'delete' operator removes properties. - - mx.utils.UIDUtil.getUID() can be used to generate a (huge) unique String - for any object for use as a key or something. - - It might be worth waiting, I think it's very probable that Adobe will - add in a Hashtable class to the standard libraries... - -- Since we cannot do streaming via reflection like we do in Java, each - Streamable class needs to define its own readObject/writeObject methods. - At one point we thought that maybe we could just write the class - and have a script examine the class definition and automatically generate - those two methods, but I don't think that's going to save us much. - Variables cannot be marked as transient, and we often have to change the - type locally: actionscript has Number and int which correspond to - float/double and int/short/byte when we stream to the server. So we'd have - to do a bunch of crazy comment annotations on each variable to be streamed - in any class and at that point we may as well just write the streamable - methods, IMO. - - -Notes ------ -- In actionscript, 'package' is simply a block command to sweep whatever is - defined inside the block so that it's in that package. This means - that in addition to classes being in a package, freestanding functions - and I believe variables and constants can be in a package. - - We are not putting freestanding functions anywhere. Make a util class with - static methods. - -- ActionScript does not have inner classes. Only one public class may be - defined in a file, and the filename must match the public class. - However, protected classes cannot be defined within the package block! - So it seems like the model is: - - package com.foo { - public class FooBar { - // stuff - } - } // end: package foo - - class HelperClass { - // helper stuff - } - - - To me, this makes it seem as if the helper class is now globally scoped, - which of course is the exact opposite of what is desired. This may - not be the case, I haven't played with it much yet. - - What especially sucks is that any imports must be repeated down below - for the helper class, including importing the class defined just above. - Again, it's unclear to me whether those imports are now globally scoped - and will spill over onto other files... What a giant pain. - - ***Update: it turns out that the primary class in a file may be declared - with internal accessibility. So HelperClass could live in its own file - and access 'internal' methods on the main class. That is probably - preferable to having them in the same file but having to re-import anyway - and accessing only public properties of the main class from the helper. - - -- Sandboxing classes is done with ApplicationDomains. When we load a sub-swf - we'll want to put it into a different domain so that nothing malicious - can be done to our classes. - -- constructors do not defaultly call super()- be sure to do it explicitely. - Maybe we should get in the habit of doing it in Java for consistency and - explicitness. - CORRECTION: super() is called implicitely, just as in Java. - -- It's annoying how there can be only one constructor: if you have classA - that has a 1-arg constructor and it is extended by classB, then the implicit - super() is inserted, but this results in runtime error because the classA - constructor is not being passed an arg. You'd think this would be caught - at compile time... - -- The RENDER Event is dispatched prior to each rendering, it's - basically like tick(): it gives anything that cares a chance to update - prior to being painted. It doesn't specify what the hell to listen on for - this event, but since all DisplayObjects are event dispatchers then - listening on any display object (including the stage) should work... - - But, the damn thing doesn't get dispatched if there will be no render, - even if the code is still running- like when the flash player window is - minimized or obscured. Lovely. - - I will play around with trying to just use a Timer with a 1ms interval, - and see if the frequency is limited to the actual framerate. - -- All methods must be marked with the 'override' keyword if they override - a method in their parent, except for toString(), even though it's defined - for Object. Apparently those methods are 'magic' and are not really in - the base class. What an annoying inconsistency. - -- 'protected' means something slightly different from java: other classes - in the same package cannot access protected members, only subclasses may: - -Java Class Package Subclass World - private Y N N N - Y Y N N - protected Y Y Y N - public Y Y Y Y - -ActionScript - private Y N N N - internal Y Y N N - protected Y N Y N - public Y Y Y Y - - -- Beware of non-existant integer math: - - var i :int = 3; - var o :Object = someArray[i / 2]; - // o is now undefined, because we accessed array element "1.5". - // I think arrays are just hashes, so probably you could store - // values at element 1.5 if you desired... - -- Similarly, methods in String take Number arguments (wha?) for character - index positions. Totally nonsensical. - -- Hey! Array has two constructors! How can I do that? - - Probably they have one constructor with varargs, and it simply checks - to see if there is only 1 arg and if it's an int, and then does something - different. Although, we can't really be sure, because these classes are - magic and special and don't have a corresponding .as file we can check out. - -- I've been casting using 'as': - var s :String = (someObject as String); - - But I've learned that there's another way that didn't seem to be listed - anywhere in the language reference but is more like what we'll want: - var s :String = String(someObject); - - The difference is that the first one tries to coerce the value to be - of the specified type, and if it fails returns null. The second is - more like a cast in Java, in that if it fails it generates an Error at - runtime. - - Note that if the types are coercable, each one will succeed in the same way: - var o :Object = 2.5; // create a Number object - var x :int = (o as int); - var y :int = int(o); - // both of these work and turn the Number 2.5 into int 2. - - Perhaps we'll want a util method that always generates an error if the - object's type is not identical or a subclass of the casted-to type. - - ***Update: - var o1 :String = null; - var o2 :String = String(o1); // ends up being "" or something - - The 2nd kind of cast destroys null, at least for String. So fuck that, - I was trying to use it when pulling a value out of a hash, but if it - wasn't there it got booched. - - ***Update: - Just not casting is "implicit casting" and will result in a type error - at runtime. This may be what we want, but it's maddening that there's - no way to do it explicitely. - - var o1 :String = someObject; - // checked at runtime, throws TypeError if failure - - Also, when the compiler is in strict mode it flags this code, so - we can't win. - - I will sum up in a table: - - * cast using "obj as Type" - + helps compile-time type checking - - turns non-castable objects into null rather than generating an exception - * casting using "Type(obj)" - + helps compile-time type checking - - will coerce primitive types between each other, the most annoying - problem being: - var o1 :Object = null; - var s1 :String = String(o1); - assert(s1 === "null"); - * implicit casting ("var s :String = o") - + it will generate a proper TypeError at runtime - - no compile-time checking, strict compiler generates an error (!!!) - - -- Pitfall! This is perfectly legal: - var b :int = 3; - var b :int = 4; - - This will generate a compile warning: - var b :int = 3; - var b :String = "three"; - It generates the warning on assigning 3 to b, because it has looked - into the future and decided that b is a String, even though it's an - int on that line. - - And: - - var b :int = 3; - for (var ii:int = 0; ii < b; ii++) { - var b :Number = 3.3; - } - trace(b); // prints "3.3", even though we've left the loop - - -- AS3.0 allows for a bit of introspection, using the function - flash.util.describeType(). The only problem is that if you pass in a Class - then it always says that it's final (I guess it's the class's Class). It - will dump information identical to the information given about an instance - except that the dynamic/final information is lost. This is preventing - me from correctly streaming arrays, as we need to know if the class - is final. I can't just pass an instance in because it may be a pain - to construct, it may even be unconstructable if the type of the array - is an interface. Posted as a request for enhancement on the AS3.0 forums. - - -- Actionscript's property accessors are a cool feature, but beware hidden - performance issues: accessing a simple property of a variable - (like myArray.length) may actually be executing arbitrary code, possibly - creating many objects, each time. - -- Classes without a constructor cannot be instantiated. This is a - runtime error (grraah!). - There is a compiler option "-compiler.warn-no-constructor" - but it generates a flotilla of warnings from standard classes in the flash - library, so it's slightly useless. - ***Update: What the heck. I noticed today that DSet has no constructor - and I've never had any trouble instantiating those. Why would not having - a constructor be an error for some classes and not others? Grraahh! - ***Update: The language spec says that a default (no arg) constructor - is created implicitely if one is not defined. Probably when I got - the error that a class had no constructor it was some sort of compiler - bug. - -- Static initializers can be emulated: - public class A - { - private static function staticInit () :void - { - // whatever - } - - staticInit(); // will be placed inside the real static initializer - } - -- Unlike in Java, most operators are overloaded for strings: - if (str1 > str2) { // compares asciibetically - -- It's pissing me off that some classes magically can use array dereferencing - ([]) to do magical things, but there is no clear indication of which classes - support it and which don't: you just have to scan through the class - documentation. Array itself is dynamic, supposedly they needed to do that - to store things in it, but it shouldn't be used as a dynamic class. Some - of the collection-type classes also support []ing as does the arguments - class. Those aren't dynamic though: they're just magical, and as far - as I can tell there's no way to grant this magic to my own classes. - I'd feel better about it if there were some marker interface implemented - by all classes that can be []'d. - -- Functions may be declared anywhere, and it seems that they have visibility - to any variables around them at that point, as if they were an inner class - and the variables were final: - - var list :ArrayCollection = new ArrayCollection(); - list.addItem(foo); - - var funcy :Function = function (i :int) :void { - Log.debug("I can see " + list[0]); - }; - _savedFunc = funcy; - - Then _savedFunc can be called at any later date and it can access list[0] - just fine. - - This just might save our butts from insane class proliferation with service - listeners. - -- You can't use runtime constants as parameter initializers: - - public const MAX_VALUE :int = 99; - - // this is illegal because MAX_VALUE is not defined until the - // static initializer is run for this class. It's not around at compile time. - public function getCrap (minValue :int, maxValue :int = MAX_VALUE) :Crap - -- Static constants are not inherited by subclasses. You can make them - prototype rather than static and they will be. - -- anonymous class options: - - - pass arrays of functions, with just a convention as to which function is - which (no compile-time type checking) - - pass objects with functions of the right names attached (no compile-time) - - make adapters, as necessary, for interfaces (bleah!) (Still no good - compile-time checking, except for the # of args) - - add code to verify the object's functions against describeType calls.. - (would need to iterate on types because describeType only finds methods - in the terminal interface. Only # of args can be checked) - -- Private constructors are not allowed, so the official line from Macromedia - on creating Singleton classes, I-shit-you-not, is to do this: - -package foo { - -public class Singleton -{ - public static const singleton :Singleton = new Singleton(new SecretClass()); - - public function Singleton (secret :SecretClass) - { - } -} -} // end: package - -public class SecretClass // inaccessible outside this file -{ -}