Search Unity

Declare a property in Javascript

Discussion in 'Scripting' started by benblo, Aug 23, 2007.

  1. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    I come from C# so I'm having a hard time with JS sometimes...
    How do I define a property that would go like this in C#:
    Code (csharp):
    1.  
    2. public string SomeString
    3. {
    4.     get { return someString; }
    5.     set { someString = value; }
    6. }
    7.  
    Or alternatively, is there a way to declare a var that would be publicly accessible from other scripts, but couldn't be set in the editor?[/code]
     
  2. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    I'm no JavaScript genius, but why not just do this:

    Code (csharp):
    1.  
    2. function SetSomeString( value )
    3. {
    4.      someString = value;
    5. }
    6.  
    7. function GetSomeString()
    8. {
    9.      return someString;
    10. }
    Or, better yet, just use C# ;)
     
  3. lgoss007

    lgoss007

    Joined:
    Dec 6, 2006
    Posts:
    88
    Code (csharp):
    1.  
    2. function get SomeString() { return someString; }
    3. function set SomeString(s) { someString = s; }
    4.  
    I believe that works. The best JavaScript docs that I know of (that are close to how Unity JavaScript works), are located here:
    http://developer.mozilla.org/es4/spec/spec.html
     
  4. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    Nope, tried it already, doesn't work.

    Back when I was into webdev I drove myself crazy for days with this property getter/setter thing, to my knowledge only Firefox supports this (probably Opera too), IE doesn't.

    And of course JScript.NET supports it too, and I thought that Unity's Javascript was JScript.NET, since it's Mono/C#/Boo and all, but apparently it's not the case. I still don't get what Javascript implementation Unity's using, or even WHY use javascript and .NET side by side... hell, why use .NET at all on a Mac environment??
    But I guess that's off-topic... hey, don't get me wrong, Unity rocks, we tried a bunch of engines and didn't decide lightly that it was the best, but man do I find these choices weird.
     
  5. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    OTEE created their own JS implementation.

    Some obvious reasons I can think of for using Mono, is speed, cross-platform ability (Windows, and room to grow to Linux), a plethora of languages to choose from to use as scripting languages. Granted, I don't like JS very much, it's an easy enough of language for inexperienced programmers and artists to get into :)

    I'm sure their are quite a bit more though!
     
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Our JS implementation is builtin ontop of .NET. It's a custom compiler we wrote ourselves (Rodrigo Oliveira has been working on it)

    The reason for using mono is primarily speed (As in running 20x faster than Mozilla based JavaScript) and the ability to interoperate with multiple languages and having an abundance of utility libraries available to people. I could keep on going with the list of advantages but those are the most important.

    The reason for building our own JS, by creating a compiler that generates .NET dll's, is because we felt that performance was extremely important. I would hate to explain to people that using C# resulted in better performance than JavaScript.

    So instead we wrote our own, which uses concepts like type inference and has very similar performance to C# and is roughly 20x faster than Mozilla based JavaScript. As far as i know it's the fastest JavaScript implementation in existance.
     
  7. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    Just out of curiosity, since you guys took the trouble to rewrite a JS implementation, why didn't OTEE decide to create their own "UnityScript"?

    Just curios :)
     
  8. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    OK, thanks everyone for the info.
    So basically, no properties in JS, uh? Is that something we can expect for Unity 2.0?

    So I guess that means that the other way around, C# isn't slower, right? Or any other MSIL-language, like Boo? If that's the case, why not use JScript.NET, or is it proprietary to Microsoft?

    Sorry about all these ramblings, but I'm still undecided as to whether I should use C#, which I prefer, or JS, which the community seems to be using more: when in Rome, do as the Romans...

    C# was my big favorite while coding for the web, but in a game environment where everything is much more dynamic and reflection is everywhere, I have to admit that JS and its type inference is a blast.



    On a related subject, I think it's really a pity that while using .NET, you don't respect their upper/lower-case conventions, ie a variable is lower-case and a function upper, while in .NET the distinction is usually made on private/public.
    I have no preference one way or the other, it's just a convention, but having both mixed-up makes Unity code heterogeneous.

    And the "Unity framework" isn't even consistent between JS and C#:
    Code (csharp):
    1. JS:
    2.     var s : String;
    3. C#:
    4.     public string s;
    5.  
    ... String, string, what's up with that?? C# in VS certainly accepts both!

    So I guess you started with JS, then included .NET, but do you plan to homogenize this in 2.0, or later? I realize backward compatibility would take a hit, but I really think it would be better in the long run.

    OK, I'm rambling again... I just like my code tidy!
     
  9. pete

    pete

    Joined:
    Jul 21, 2005
    Posts:
    1,647
    >>whether I should use C#, which I prefer, or JS

    makes zero difference. use c#. cheers!
     
  10. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    If I were you, I'd use C#. Using JS type inference can be slow.

    The thing with the strings you pointed out isn't OTEE's fault.

    "String" is a .NET type (so you can do var myString: String = " "; in JS and String myString = " "; in C#. The 'string' type your seeing in C# is an alias for 'String'. Check out http://msdn2.microsoft.com/en-us/library/362314fe(VS.71).aspx for proof :p
     
  11. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    Good advice, I'll take it into consideration. It's certainly less frustrating to write more code if you know it's worth it ;) !

    Well, exactly, string is an alias for String (same with int/Int32, bool/Boolean), so why does it throw a compile error when you use the "real" type instead of the alias?

    Try this:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class NewBehaviourScript : MonoBehaviour {
    5.  
    6.     string s;
    7.     String S;     // doesn't compile
    8. }
    I get the following:
    Code (csharp):
    1. The type or namespace name 'String' could not be found.
     
  12. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    Add
    Code (csharp):
    1. using System;
     
  13. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    :oops: :oops: :oops:
    ... of course!!
    I was so used to VS always putting in on top of all classes...
     
  14. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Actually it's not, and anyway it only happens at compile time. Dynamic typing can be slow (which is something quite different from type inference), but just put "#pragma strict" at the top of your script if you want to make sure it never happens. Use whatever you like, of course, but I'd recommend JS because the type inference, among other things, makes writing code less annoying (and, again, makes no speed difference whatsoever). I've found there are some areas where you have to go through some contortions in C#. You can't do this, for example:

    Code (csharp):
    1. transform.position.x += .5;
    Instead you have to do this:

    Code (csharp):
    1. Vector3 pos = transform.position;
    2. pos.x += .5f;
    3. transform.position = pos;
    I prefer "just doing stuff" rather than having to fight with the code like that.

    --Eric
     
  15. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    Hmmm, I thought type inference was the same as Dynamic typing.
    So, what is type inference?
     
  16. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Type inference is this:

    Code (csharp):
    1. var someString = "Blah";
    This is inferred at compile time to be a string, and it has no performance penalty. Using "#pragma strict" will have no effect, since it's statically typed. It's exactly the same thing as this:

    Code (csharp):
    1. var someString : String = "Blah;"
    This is why I prefer type inference...of course it's a darn string and it's completely obvious, why should I have to specify that when the compiler can figure it out? ;) Usually the only time I really specify types is with floats/ints, just to be absolutely clear.

    (Since you can run into trouble if you mix those up. For example, "var someNum = .5;" is inferred to be a float, but if I later change that to "var someNum = 1;" instead of "var someNum = 1.0", then it's inferred to be an int, and that might screw up the code. So to play it safe I'd write "var someNum : float = 1.0;" in case I get forgetful or lazy and write an integer there later when I really need it to be a float.)

    Dynamic typing is this:

    Code (csharp):
    1. function OnCollisionEnter(collision : Collision) {
    2.     if (collision.collider.name == "Blah") {//whatever}
    3. }
    Using "#pragma strict" will cause this to not compile since it's figuring out the type on the fly every time the function is called. Instead you'd do this:

    Code (csharp):
    1. #pragma strict
    2.  
    3. function OnCollisionEnter(collision : Collision) {
    4.     var col : Collider = collision.collider;
    5.     if (col.name == "Blah") {//whatever}
    6. }
    So it does take an extra step to statically type this, in this case. But in my scripts, anyway, I've found that dynamic typing isn't common at all, and if it's being done in a function that's called rarely, it's not really worth the bother of fixing it.

    Here's another example of dynamic typing:

    Code (csharp):
    1. var script = GetComponent(MyScript);
    2. script.SomeFunction();
    Since it has to figure out the type on the fly. In this case you can make it statically typed just by changing it to:

    Code (csharp):
    1. var script : MyScript = GetComponent(MyScript);
    2. script.SomeFunction();
    --Eric
     
  17. drJones

    drJones

    Joined:
    Oct 19, 2005
    Posts:
    1,351
    not surprisingly, i had no idea about this ; )

    if you don't mind elaborating a bit, any function like the first example (with an argument) is dynamically typed? and for these functions that are called alot this will help with performance?
     
  18. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Well, no, in that example it's only "collision.collider.name" that's dynamically typed, since it's having to figure the type Collider on the fly. The variable "collision" of type Collision (yeah, possibly confusing naming there ;) ) is statically typed.

    If I were to do

    Code (csharp):
    1. function OnCollisionEnter(collision : Collision) {
    2.     if (collision.rigidbody) {//Whatever}
    3. }
    4.  
    for example, there's no dynamic typing there, since I've already specified the type Collision and there are no other types involved.

    Yep. For something that's called only once in a while and it's dynamically typed, but that makes the code simpler, then who really cares if it takes some nanoseconds longer to execute? If you have something computationally intensive, though, then it makes sense to ensure it's statically typed. Thus I tend to put "#pragma strict" at the top of any scripts that use functions that are called every frame, or for heavy setup code that I want to run as fast as possible. This will catch any instances of dynamic typing that I might have overlooked. (To me, anyway, it's not always immediately obvious.)

    --Eric
     
  19. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    Hmm, I don't see how if (collision.collider.name == "Blah") is dynamic at all. collision.collider.name type should be known at the runtime (the compiler).

    Unless this type inference is specific to OTEE's implementation, I've always known this var someString = "Blah"; to be dynamic typing.
     
  20. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It's not quite that simple, but it doesn't really matter anyway; just put "#pragma strict" in all scripts if you never want to deal with dynamic typing.

    Yep, it is! They've talked about this in various topics before. It's one of the cool features.

    Yeah, that's just with "normal" Javascript and does not apply to Unity. I think maybe whoever suggested it was right, and it should have been called Unityscript. ;)

    --Eric
     
  21. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    Alas! Now everything makes sense :D

    Thanks Erich!
     
  22. drJones

    drJones

    Joined:
    Oct 19, 2005
    Posts:
    1,351
    thank you both - very useful info ; )
     
  23. MatthewW

    MatthewW

    Joined:
    Nov 30, 2006
    Posts:
    1,356
    The collider.name example isn't dynamic, I don't think (although I haven't tested compiling with #pragma strict). It's working in the known direction of inheritance (Collider -> Component -> Object.name).

    Dynamic typing can work in the opposite, "unknown" direction of inheritance. One example would be:

    Code (csharp):
    1.  
    2. gameObject.GetComponent(YourScript).YourFunction();
    3.  
    GetComponent() returns a Component, so here the compiler has to figure out that it's actually returning a specific type YourScript, which is extending Component at some point (YourScript -> MonoBehaviour -> Component). Notice the path goes in the other direction from the above example.

    In C# you'd have to do:

    Code (csharp):
    1.  
    2. YourScript temp = gameObject.GetComponent(typeof(YourScript)) as YourScript;
    3. temp.YourFunction();
    4.  
    Or, in one line:

    Code (csharp):
    1.  
    2. (gameObject.GetComponent(typeof(YourScript)) as YourScript).YourFunction();
    3.  
    Horrors!

    We recently moved from C# to JS for shorter code and less back-and-forth porting with the examples.

    Disclaimer: The above is just my understanding as a user and may be completely wrong ;)
     
  24. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I have; it doesn't work. :) You get basically the same error as you would with your example, if you tried compiling with #pragma strict. Remember, it's not just collider.name (which would be fine), it's collision.collider.name. Still, it probably wasn't the best example, which I why I gave another one below.

    Mind you, I wouldn't want to discourage anyone from working with C# if that's what you're comfortable with (even if I personally don't care for it). It's a perfectly valid choice; it's just that I wanted to clear up a little misunderstanding about Javascript in Unity.

    --Eric
     
  25. jeremyace

    jeremyace

    Joined:
    Oct 12, 2005
    Posts:
    1,661
    Just to throw another bit of info into the pile, one area which really pains me in JS is OOP.

    IMO, JS can't compete with C# for _proper_ OOP. When you are coding a massive beast and want to reuse code, that can be extremely useful (critical for large projects IMO).

    I am not saying you can't get a similar end result in JS, I am sure you can, and some people do, but if you are coming from a more traditional mindset, you will probably get irked quickly trying to design your code like you are used to (and like it should be designed IMO).

    This is of course just my personal preference, and it has a lot to do with how you design your systems.

    If I were you, I'd play around with both JS and C# in Unity and see which you prefer. And as for converting JS samples to C#, it isn't hard as you already know C# and the API is the same for both.

    -Jeremy
     
  26. David-Helgason

    David-Helgason

    Moderator

    Joined:
    Mar 29, 2005
    Posts:
    1,104
    You can create classes and make inheritance in JavaScript. You simply wrap up your classes like this:

    Code (csharp):
    1. class MyThing extends MonoBehaviour {
    2.    var s = "foobar";
    3.    var n = 1.5;
    4.    function Update() {
    5.        Debug.Log("Updated!");
    6.    }
    7. }
    You could also make classes that don't inherit from MonoBehaviour, or inherit from each other.

    d.
     
  27. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    Thanks everyone for all that info...

    Just to clarify, for those that are confused by this (as I was at first), I think this example is indeed VERY particular. Dynamic typing doesn't happen all the time, you can have long chains with no dynamic typing; if your classes do specify the types of the variables, no problem.
    The reason it doesn't work in this case is because, as Eric said, collision.collider's type is unknown (System.Object), probably because there are several collider types (cube, sphere, etc) and they don't inherit from a base class (which maybe they should, but that's not the point, and maybe that's the PhysX API's fault and not Unity's).

    If instead you use collision.transform, the compiler knows its type is Transform and that it has a name variable.
    Code (csharp):
    1. #pragma strict  // everything compiles if you remove this line
    2.  
    3. function OnCollision(col : Collision)
    4. {
    5.     var bad = col.collider.name;                        // dynamic, doesn't compile
    6.     var good = col.transform.name;                      // static, no problem
    7.     var x = col.transform.guiText.pixelOffset.x;        // long static chain, no problem either
    8. }

    As for the JS vs C# battle, the more I see, the more I think C# isn't flexible enough in a game environment. I was ok with doing without dynamic typing and having to cast everything explicitly in the context of the ASP.NET framework, but with Unity's component-based framework, it's really a LOT more lines of code!
    Also the thing that kills me most is the inability to write this : transform.position.x = 0... that's just too inconvenient!
    And that's really built into the language (I think it has to do with structs), there's nothing anyone can do about it, I remember having to deal with it once in a while, but of course in a webpage objects don't move around as much as in a game :D

    As for JS, it got a pretty bad reputation as a non-OO language with its web implementations, but I don't think it's due to the language itself, and Unity's implementation seem to be A-ok OO.
     
  28. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Actually, Collision.collider is of type Collider, which inherits from Component, which in turn inherits from Object, which has the member name, which is of type String. So there shouldn't be any dynamic typing going on at all.

    Dynamic typing should only be an issue if you are trying to reference a member specific to a subclass of Collider, such as BoxCollider.size. In this case, Collision.collider must be assumed to have the type BoxCollider in order for the code to make sense.
     
  29. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    I agree with the principle, it shouldn't. But then why do I get a compile error with #pragma strict?
    Code (csharp):
    1. error BCE0019: 'name' is not a member of 'System.Object'.
    Just when I thought I finally understood this dynamic typing thing :? ...
     
  30. jeremyace

    jeremyace

    Joined:
    Oct 12, 2005
    Posts:
    1,661
    Yep, but my crit has to do with the way you do it, and the actual supported features. I am not knocking JS as a whole, I just don't like it so I added my $.05.

    I am used to more C++ - like development, so no wonder I like C# better, heh.

    -Jeremy