Custom Objects and Classes for Scripting 2005-03-27 - By Brad Friedman
Back Thanks. Thats a ton to chew on.
re: JScript.Net:
I looked into it a bit a while ago but its just yet another reworked language hooked into the .net CLR. So when you are programming in JScript.Net you are stuck with the .net COM Interop rather than the super nice and fuzzy activex native situation you are in with pure JScript on its own. They try to hide it but thats what you are doing none the less, and it does reach up and bite you. Its a tradeoff.
Personally, I'd really like to see softimage wrap the pure C++ API in a P-Invoke assembly, for use with Mono and the microsoft .net runtime. Then I'd like to see them allow plugin registration callbacks into a .net assembly. That would open up every language thats been hooked into the CLR, including Java, Python, C#, VB, JScript.Net, you name it, for both windows and linux, without a confusing porting solution mixed in. And it would do so in a strongly typed manner, allowing for effective JIT compiled solutions. But thats just me wishing. I don't expect it to happen. Mono and the CLR are mired in programmer politics these days.
-brad
Bradley R. Gabe wrote:
>> which makes sense. But I was wondering about the instantiation of >> the object itself. First of all, what are some of the best standards >> and practices of creating objects in jscript? My understanding is >> that there are a couple of ways to do it and I was wondering if >> anyone has any reason why one way in particular is better for XSI. > > > From recent experience, I've learned that it is necessary to structure > your object instatiation such that you can use the same call inside > XSI, or ouside XSI in javascript land for netview development. For > typical javascript object instatiation, after the class file is > included into the current script, the following syntax is required: > > //Instantiate an included custom object in a netview script > var obj = new CustomObject(); > > In XSI, including a file into your current script is slow compared to > just registering the command and calling it directly. Since calling > commands is an XSi thing and not a jscript thing, jscript is not going > to recognize your custom command with respect to the 'new' call. Your > command has to return the new instance so you don't need the 'new' call: > > //Instantiate a custom object from an XSI command > var obj = CustomObject(); > > As an addendum to my blog entry, I need to talk about structuring the > instantiate such that your custom objects can work inside XSI, or > inside netview javascript in a seamless fashion. While I suspect there > are more elegant ways to do it (perhaps going all Python would be > one), I've found that I can overcome the difference between XSI and > javascript object instantiation by splitting my constructor into 2 > separate functions. This allows me to use the exact same call, whether > I'm running from within an XSI command or from a javascript doing a > netview. > > The first function is a class template which only defines the > properties and methods. > The second function does the instantiation and construction and > returns the new class instance. > > From within XSI, I parse the command and tell it to run the second > function as the command procedure. > From within javascript, after the file is included, I can run the > second function the same way I would within XSI. > > The other thing I've discovered is that a separate constructor > function makes it easier to overload your object input and decide > whether or not to return an object if the input is bad. In the example > below, I use the constructor function to test the input and set class > properties based on input type, or log errors and return a null object > if the input is invalid: > > // CLASS TEMPLATE > function Class_CustomObject(inputValue) > { > // Class Properties -- ---- ---- ---- ---- ------ > this.type = 'CustomObject'; > this.size = 0; > this.Model = null; > this.description = ''; > > // Class Methods -- ---- ---- ---- ---- -- > this.SetSize = CustomObject_SetSize; > this.GetModel = CustomObject_GetModel; > this.LogError = CustomObject_LogError; > } > > // CLASS CONSTRUCTOR > function CustomObject(inputValue) > { > // Get pointers to application for netview > var xsi = new ActiveXObject('XSI.Application'); > var app = xsi.Application; > > // Instantiate a new object > var obj = new CustomObject(); > > // Based on inputValue, return something > -- ---- ---- ---- ---- ------ > > // If user provides no input, do not instantiate > if(!inputValue) return(null); > > // If user inputs a number, set the size property > if(typeof(inputValue) == 'number'){ > obj.size = inputValue; > return(obj); > } > > // If user inputs an object and it is a #model, point the > Model property to it > else if(typeof(inputValue) == 'object' && inputValue.type == > '#model){ > obj.Model = inputValue; > return(obj); > } > > // If we got this far, input is not a valid type > app.LogMessage('CustomObject(Argument[0]) -- Invalid input', 2); > return(false); > } > > >> I intend to roll an object as a utility library of functions (as >> suggested as one possible use in the blog entry). If I'm >> understanding the example, I think thats what GUITools is doing as >> well. Am I to understand that the object is instantiated every time >> the "GUITools" command is called? Or is it cache'ing it somewhere in >> global memory the first time and just passing the same instance on >> subsequent calls? Or is the instantiation so cheap, it doesn't >> matter that you instantiate it in every function you use it in? Is >> there a good place to toss an object where it will persist for the >> remainder of the given XSI session? Or is that foolhearty? > > > I ran into some problems with this technique recently after stacking > too many objects too deep. While it was never an issue in XSI 3.5 on > linux, it seems that with the changes to command registration in XSI > 4+ and on windows, one must be cautious about treating jscript too > much like a real programming language. > > An important aspect to know about jscript is that its object > functionality is a bit of a hack. In C++, Java, and other compiled > languages when you instantiate an object, you get a separate memory > space and control over your construction and destruction. Inheritance > and polymorphism is stable and reliable to many levels deep. > > In jscript, the whole object functionality is a clever hack in the > language, using arrays and string copies of your functions. Methods, > for example, are simply pointers to your function stored as a string > in an array. When you call the method, jscript runs an eval() on your > function string, then runs the function. When you include an ancestor > object into your current object, jscript loads in the file and does > string concatenation at runtime. > > What this means is that you should be really careful about nesting > objects inside other objects too many levels deep. 2 or 3 levels is > okay, but any more than that and you are risking a jscript meltdown at > runtime. Test your stuff early and often, especially for performance > in order to prevent unexpected problems. The moment you run into > strange and unexplainable variable scope issues, you've gone too many > levels deep and you'll have to explode some of your earliest objects. > > Other scripting languages, such as Python and Php are built around > this kind of object component construction, and don't suffer the same > isses. However, I have heard some rumors about a compilable version of > jscript, so perhaps the future for jscript and OOP may be better. > > > >> thanks, >> -brad >> --- >> Unsubscribe? Mail Majordomo@(protected) with the following text in >> body: >> unsubscribe xsi >
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html;charset=ISO-8859 (See http://ISO-8859.ora-code.com)-1" http-equiv="Content-Type"> <title></title> </head> <body bgcolor="#ffffff" text="#000000"> Thanks. Thats a ton to chew on.<br> <br> re: JScript.Net:<br> <br> I looked into it a bit a while ago but its just yet another reworked language hooked into the .net CLR. So when you are programming in JScript.Net you are stuck with the .net COM Interop rather than the super nice and fuzzy activex native situation you are in with pure JScript on its own. They try to hide it but thats what you are doing none the less, and it does reach up and bite you. Its a tradeoff.<br> <br> Personally, I'd really like to see softimage wrap the pure C++ API in a P-Invoke assembly, for use with Mono and the microsoft .net runtime. Then I'd like to see them allow plugin registration callbacks into a .net assembly. That would open up every language thats been hooked into the CLR, including Java, Python, C#, VB, JScript.Net, you name it, for both windows and linux, without a confusing porting solution mixed in. And it would do so in a strongly typed manner, allowing for effective JIT compiled solutions. But thats just me wishing. I don't expect it to happen. Mono and the CLR are mired in programmer politics these days.<br> <br> -brad<br> <br> Bradley R. Gabe wrote: <blockquote cite="mid6.1.2.0.0.20050326191706.053c7078@(protected)" type="cite"> <blockquote type="cite" class="cite" cite="">which makes sense. But I was wondering about the instantiation of the object itself. First of all, what are some of the best standards and practices of creating objects in jscript? My understanding is that there are a couple of ways to do it and I was wondering if anyone has any reason why one way in particular is better for XSI.</blockquote> <br> >From recent experience, I've learned that it is necessary to structure your object instatiation such that you can use the same call inside XSI, or ouside XSI in javascript land for netview development. For typical javascript object instatiation, after the class file is included into the current script, the following syntax is required:<br> <br> <font color="#008000" face="Courier New, Courier">//Instantiate an included custom object in a netview script<br> </font><font face="Courier New, Courier">var obj = new CustomObject();<br> <br> </font>In XSI, including a file into your current script is slow compared to just registering the command and calling it directly. Since calling commands is an XSi thing and not a jscript thing, jscript is not going to recognize your custom command with respect to the 'new' call. Your command has to return the new instance so you don't need the 'new' call:<br> <br> <font color="#008000" face="Courier New, Courier">//Instantiate a custom object from an XSI command<br> </font><font face="Courier New, Courier">var obj = CustomObject();<br> <br> </font>As an addendum to my blog entry, I need to talk about structuring the instantiate such that your custom objects can work inside XSI, or inside netview javascript in a seamless fashion. While I suspect there are more elegant ways to do it (perhaps going all Python would be one), I've found that I can overcome the difference between XSI and javascript object instantiation by splitting my constructor into 2 separate functions. This allows me to use the exact same call, whether I'm running from within an XSI command or from a javascript doing a netview.<br> <br> The first function is a class template which only defines the properties and methods.<br> The second function does the instantiation and construction and returns the new class instance.<br> <br> >From within XSI, I parse the command and tell it to run the second function as the command procedure.<br> >From within javascript, after the file is included, I can run the second function the same way I would within XSI.<br> <br> The other thing I've discovered is that a separate constructor function makes it easier to overload your object input and decide whether or not to return an object if the input is bad. In the example below, I use the constructor function to test the input and set class properties based on input type, or log errors and return a null object if the input is invalid:<br> <br> <font color="#008000" face="Courier New, Courier">// CLASS TEMPLATE<br> </font><font face="Courier New, Courier">function Class_CustomObject(inputValue)<br> {<br> <x-tab> </x-tab></font><font color="#008000" face="Courier New, Courier">// Class Properties -- ---- ---- ---- ---- ------<br> </font><font face="Courier New, Courier"><x-tab>   ; </x-tab>this.type = 'CustomObject';<x-tab> </x-tab><br> <x-tab> </x-tab>this.size = 0;<br> <x-tab> </x-tab>this.Model = null;<br> <x-tab> </x-tab>this .description = '';<br> <br> <x-tab> </x-tab></font><font color="#008000" face="Courier New, Courier">// Class Methods -- ---- ---- ---- ---- --<br> </font><font face="Courier New, Courier"><x-tab>   ; </x-tab>this.SetSize = CustomObject_SetSize;<br> <x-tab> </x-tab>this.GetModel = CustomObject_GetModel;<br> <x-tab> </x-tab>this.LogError = CustomObject_LogError;<br> }<br> <br> </font><font color="#008000" face="Courier New, Courier">// CLASS CONSTRUCTOR<br> </font><font face="Courier New, Courier">function CustomObject(inputValue)<br> {<br> <x-tab> </x-tab></font><font color="#008000" face="Courier New, Courier">// Get pointers to application for netview<br> </font><font face="Courier New, Courier"><x-tab>   ; </x-tab>var xsi = new ActiveXObject('XSI.Application');<br> <x-tab> </x-tab>var app = xsi.Application;<br> <br> <x-tab> </x-tab></font><font color="#008000" face="Courier New, Courier">// Instantiate a new object<br> </font><font face="Courier New, Courier"><x-tab>   ; </x-tab>var obj = new CustomObject();<br> <br> <x-tab> </x-tab></font><font color="#008000" face="Courier New, Courier">// Based on inputValue, return something -- ---- ---- ---- ---- ------<br> <br> </font><font face="Courier New, Courier"><x-tab>   ; </x-tab></font><font color="#008000" face="Courier New, Courier">// If user provides no input, do not instantiate<br> </font><font face="Courier New, Courier"><x-tab>   ; </x-tab>if(!inputValue) return(null);<br> <br> <x-tab> </x-tab></font><font color="#008000" face="Courier New, Courier">// If user inputs a number, set the size property<br> </font><font face="Courier New, Courier"><x-tab>   ; </x-tab>if(typeof(inputValue) == 'number'){<br> <x-tab> </x-tab><x-tab> </x-tab>obj.size = inputValue;<br> <x-tab> </x-tab><x-tab> </x-tab>return(obj);<br> <x-tab> </x-tab>}<br> <br> <x-tab> </x-tab></font><font color="#008000" face="Courier New, Courier">// If user inputs an object and it is a #model, point the Model property to it<br> </font><font face="Courier New, Courier"><x-tab>   ; </x-tab>else if(typeof(inputValue) == 'object' && inputValue.type == '#model){<br> <x-tab> </x-tab><x-tab> </x-tab>obj.Model = inputValue;<br> <x-tab> </x-tab><x-tab> </x-tab>return(obj);<br> <x-tab> </x-tab>}<br> <x-tab> </x-tab><br> <x-tab> </x-tab></font><font color="#008000" face="Courier New, Courier">// If we got this far, input is not a valid type<br> </font><font face="Courier New, Courier"><x-tab>   ; </x-tab>app.LogMessage('CustomObject(Argument[0]) -- Invalid input', 2);<br> <x-tab> </x-tab>return(false); <br> }<br> <br> <br> </font> <blockquote type="cite" class="cite" cite="">I intend to roll an object as a utility library of functions (as suggested as one possible use in the blog entry). If I'm understanding the example, I think thats what GUITools is doing as well. Am I to understand that the object is instantiated every time the "GUITools" command is called? Or is it cache'ing it somewhere in global memory the first time and just passing the same instance on subsequent calls? Or is the instantiation so cheap, it doesn't matter that you instantiate it in every function you use it in? Is there a good place to toss an object where it will persist for the remainder of the given XSI session? Or is that foolhearty?</blockquote> <br> I ran into some problems with this technique recently after stacking too many objects too deep. While it was never an issue in XSI 3.5 on linux, it seems that with the changes to command registration in XSI 4+ and on windows, one must be cautious about treating jscript too much like a real programming language.<br> <br> An important aspect to know about jscript is that its object functionality is a bit of a hack. In C++, Java, and other compiled languages when you instantiate an object, you get a separate memory space and control over your construction and destruction. Inheritance and polymorphism is stable and reliable to many levels deep.<br> <br> In jscript, the whole object functionality is a clever hack in the language, using arrays and string copies of your functions. Methods, for example, are simply pointers to your function stored as a string in an array. When you call the method, jscript runs an eval() on your function string, then runs the function. When you include an ancestor object into your current object, jscript loads in the file and does string concatenation at runtime.<br> <br> What this means is that you should be really careful about nesting objects inside other objects too many levels deep. 2 or 3 levels is okay, but any more than that and you are risking a jscript meltdown at runtime. Test your stuff early and often, especially for performance in order to prevent unexpected problems. The moment you run into strange and unexplainable variable scope issues, you've gone too many levels deep and you'll have to explode some of your earliest objects.<br> <br> Other scripting languages, such as Python and Php are built around this kind of object component construction, and don't suffer the same isses. However, I have heard some rumors about a compilable version of jscript, so perhaps the future for jscript and OOP may be better. <br> <br> <br> <br> <blockquote type="cite" class="cite" cite="">thanks,<br> -brad<br> ---<br> Unsubscribe? Mail <a class="moz-txt-link-abbreviated" href="mailto:Majordomo @(protected)">Majordomo@(protected)</a> with the following text in body:<br> unsubscribe xsi</blockquote> </blockquote> <br> </body> </html>
|
|