diff options
Diffstat (limited to 'haxe.html.markdown')
| -rw-r--r-- | haxe.html.markdown | 426 | 
1 files changed, 365 insertions, 61 deletions
| diff --git a/haxe.html.markdown b/haxe.html.markdown index 90b2e250..f4694fcb 100644 --- a/haxe.html.markdown +++ b/haxe.html.markdown @@ -16,40 +16,62 @@ references.     Welcome to Learn Haxe 3 in 15 minutes.  http://www.haxe.org     This is an executable tutorial.  You can compile and run it using the haxe     compiler, while in the same directory as LearnHaxe.hx: -   haxe -main LearnHaxe3 -x out - */ +   $> haxe -main LearnHaxe3 -x out -// Let's start with comments... this is a single line comment +   Look for the slash-star marks surrounding these paragraphs.  We are inside +   a "Multiline comment".  We can leave some notes here that will get ignored +   by the compiler. + +   Multiline comments are also used to generate javadoc-style documentation for +   haxedoc.  They will be used for haxedoc if they immediately precede a class, +   class function, or class variable. -/* -   And this is multiline. Multiline comments are also used to generate -   javadoc-style documentation for haxedoc.  They will be used if they precede -   a class, class function, or class variable.   */ +// Double slashes like this will give a single-line comment + +  /* -   A package declaration isn't necessary, but it's useful if you want to -   organize your code into modules later on.  Also worth mentioning, all -   expressions in Haxe must end in a semicolon: +   This is your first actual haxe code coming up, it's declaring an empty +   package.  A package isn't necessary, but it's useful if you want to create a +   namespace for your code (e.g. org.module.ClassName).   */  package; // empty package, no namespace. - -// if you import code from other files, it must be declared before the rest of -// the code. +/* +   Packages define modules for your code. Each module (e.g. org.module) must +   be lower case, and should exist as a folder structure containing the class. +   Class (and type) names must be capitalized. E.g, the class "org.module.Foo" +   should have the folder structure org/module/Foo.hx, as accessible from the +   compiler's working directory or class path. + +   If you import code from other files, it must be declared before the rest of +   the code.  Haxe provides a lot of common default classes to get you started: + */  import haxe.ds.ArraySort;  // you can import many classes/modules at once with "*"  import haxe.ds.*; -// you can also import classes in a special way, enabling them to extend the -// functionality of other classes.  More on this later. +/* +   You can also import classes in a special way, enabling them to extend the +   functionality of other classes like a "mixin".  More on 'using' later. + */  using StringTools; -// Haxe files typically define classes, although they can also define other -// types of code... more on that later. +/* +   Typedefs are like variables... for types.  They must be declared before any +   code.  More on this later. + */ +typedef FooString = String; +// Typedefs can also reference "structural" types, more on that later as well. +typedef FooObject = { foo: String }; +/* +   Here's the class definition.  It's the main class for the file, since it has +   the same name (LearnHaxe3). + */  class LearnHaxe3{      /*         If you want certain code to run automatically, you need to put it in @@ -58,6 +80,7 @@ class LearnHaxe3{         arguments above.       */      static function main(){ +          /*             Trace is the default method of printing haxe expressions to the             screen.  Different targets will have different methods of @@ -67,8 +90,6 @@ class LearnHaxe3{             Finally, It's possible to prevent traces from showing by using the             "--no-traces" argument on the compiler.           */ - -          trace("Hello World, with trace()!");          /* @@ -76,16 +97,11 @@ class LearnHaxe3{             a representation of the expression as best it can.  You can also             concatenate strings with the "+" operator:           */ -        trace( -            " Integer: " + 10 + -            " Float: " + 3.14 + -            " Boolean: " + true -            ); - +        trace( " Integer: " + 10 + " Float: " + 3.14 + " Boolean: " + true);          /* -           Remember what I said about expressions needing semicolons? You -           can put more than one expression on a line if you want. +           In Haxe, it's required to separate expressions in the same block with +           semicolons.  But, you can put two expressions on one line:           */          trace('two expressions..'); trace('one line'); @@ -99,7 +115,6 @@ class LearnHaxe3{             You can save values and references to data structures using the             "var" keyword:           */ -          var an_integer:Int = 1;          trace(an_integer + " is the value for an_integer"); @@ -111,7 +126,6 @@ class LearnHaxe3{             the haxe compiler is inferring that the type of another_integer             should be "Int".           */ -          var another_integer = 2;          trace(another_integer + " is the value for another_integer"); @@ -137,8 +151,14 @@ class LearnHaxe3{          var a_string = "some" + 'string';  // strings can have double or single quotes          trace(a_string + " is the value for a_string"); +        /* +           Strings can be "interpolated" by inserting variables into specific +           positions.  The string must be single quoted, and the variable must +           be preceded with "$".  Expressions can be enclosed in ${...}. +         */          var x = 1;          var an_interpolated_string = 'the value of x is $x'; +        var another_interpolated_string = 'the value of x + 1 is ${x + 1}';          /*             Strings are immutable, instance methods will return a copy of @@ -149,6 +169,12 @@ class LearnHaxe3{          trace(a_sub_string + " is the value for a_sub_string");          /* +           Regexes are also supported, but there's not enough space to go into +           much detail. +         */ +        trace((~/foobar/.match('foo')) + " is the value for (~/foobar/.match('foo')))"); + +        /*             Arrays are zero-indexed, dynamic, and mutable.  Missing values are             defined as null.           */ @@ -191,7 +217,7 @@ class LearnHaxe3{          trace(m3 + " is the value for m3");          /* -           Haxe has many more common datastructures in the haxe.ds module, such as +           Haxe has some more common datastructures in the haxe.ds module, such as             List, Stack, and BalancedTree           */ @@ -199,7 +225,6 @@ class LearnHaxe3{          //////////////////////////////////////////////////////////////////          // Operators          ////////////////////////////////////////////////////////////////// -          trace("***OPERATORS***");          // basic arithmetic @@ -218,7 +243,7 @@ class LearnHaxe3{          trace((3 >= 2) + " is the value for 3 >= 2");          trace((3 <= 2) + " is the value for 3 <= 2"); -        //bitwise operators +        // standard bitwise operators          /*          ~       Unary bitwise complement          <<      Signed left shift @@ -252,6 +277,27 @@ class LearnHaxe3{              trace("also not printed.");          } +        // there is also a "ternary" if: +        (j == 10) ?  trace("equals 10") : trace("not equals 10"); + +        /* +           Finally, there is another form of control structures that operates +           at compile time:  conditional compilation. +         */ +#if neko +        trace('hello from neko'); +#elseif js +        trace('hello from js'); +#else +        trace('hello from another platform!'); +#end +        /* +           The compiled code will change depending on the platform target. +           Since we're compiling for neko (-x or -neko), we only get the neko +           greeting. +         */ + +          trace("Looping and Iteration");          // while loop @@ -310,13 +356,14 @@ class LearnHaxe3{             generalized algebraic data types in enums (more on enums later).             Here's some basic value examples for now:           */ -        var my_dog_name = 'fido'; -        var favorite_thing  = ''; +        var my_dog_name = "fido"; +        var favorite_thing  = "";          switch(my_dog_name){ -            case "fido" : favorite_thing = 'bone'; -            case "rex" :  favorite_thing = 'shoe'; -            case "spot" : favorite_thing = 'tennis ball'; -            case _ : favorite_thing = 'some unknown treat'; +            case "fido" : favorite_thing = "bone"; +            case "rex"  : favorite_thing = "shoe"; +            case "spot" : favorite_thing = "tennis ball"; +            default     : favorite_thing = "some unknown treat"; +            // case _   : "some unknown treat"; // same as default          }          // The "_" case above is a "wildcard" value          // that will match anything. @@ -345,10 +392,10 @@ class LearnHaxe3{          trace("K equals ", k); // outputs 10          var other_favorite_thing = switch(my_dog_name) { -            case "fido" : 'teddy'; -            case "rex" :  'stick'; -            case "spot" : 'football'; -            case _ : 'some unknown treat'; +            case "fido" : "teddy"; +            case "rex"  : "stick"; +            case "spot" : "football"; +            default     : "some unknown treat";          }          trace("My dog's name is" + my_dog_name @@ -358,6 +405,7 @@ class LearnHaxe3{          //////////////////////////////////////////////////////////////////          // Converting Value Types          ////////////////////////////////////////////////////////////////// +        trace("***CONVERTING VALUE TYPES***");          // You can convert strings to ints fairly easily. @@ -372,33 +420,93 @@ class LearnHaxe3{          true + ""; // returns "true";          // See documentation for parsing in Std for more details. + +        ////////////////////////////////////////////////////////////////// +        // Dealing with Types +        ////////////////////////////////////////////////////////////////// + +        /* + +           As mentioned before, Haxe is a statically typed language.  All in +           all, static typing is a wonderful thing.  It enables +           precise autocompletions, and can be used to thoroughly check the +           correctness of a program.  Plus, the Haxe compiler is super fast. + +           *HOWEVER*, there are times when you just wish the compiler would let +           something slide, and not throw a type error in a given case. + +           To do this, Haxe has two separate keywords.  The first is the +           "Dynamic" type: +         */ +        var dyn: Dynamic = "any type of variable, such as this string"; + +        /* +           All that you know for certain with a Dynamic variable is that the +           compiler will no longer worry about what type it is. It is like a +           wildcard variable:  You can pass it instead of any variable type, +           and you can assign any variable type you want. + +           The other more extreme option is the "untyped" keyword: +         */ + +            untyped { +                var x:Int = 'foo'; // this can't be right! +                var y:String = 4; // madness! +            } + +        /* +           The untyped keyword operates on entire *blocks* of code, skipping +           any type checks that might be otherwise required. This keyword should +           be used very sparingly, such as in limited conditionally-compiled +           situations where type checking is a hinderance. + +           In general, skipping type checks is *not* recommended.  Use the +           enum, inheritance, or structural type models in order to help ensure +           the correctness of your program.  Only when you're certain that none +           of the type models work should you resort to "Dynamic" or "untyped". +         */ +          //////////////////////////////////////////////////////////////////          // Basic Object Oriented Programming          //////////////////////////////////////////////////////////////////          trace("***BASIC OBJECT ORIENTED PROGRAMMING***"); -        // create an instance of FooClass.  The classes for this are at the -        // end of the file. -        var instance = new FooClass(3); +        /* +           Create an instance of FooClass.  The classes for this are at the +           end of the file. +         */ +        var foo_instance = new FooClass(3);          // read the public variable normally -        trace(instance.public_any + " is the value for instance.public_any"); +        trace(foo_instance.public_any + " is the value for foo_instance.public_any");          // we can read this variable -        trace(instance.public_read + " is the value for instance.public_read"); +        trace(foo_instance.public_read + " is the value for foo_instance.public_read");          // but not write it -        // instance.public_write = 4; // this will throw an error if uncommented: -        // trace(instance.public_write); // as will this. +        // foo_instance.public_write = 4; // this will throw an error if uncommented: +        // trace(foo_instance.public_write); // as will this. + +        trace(foo_instance + " is the value for foo_instance"); // calls the toString method +        trace(foo_instance.toString() + " is the value for foo_instance.toString()"); // same thing -        trace(instance + " is the value for instance"); // calls the toString method -        trace(instance.toString() + " is the value for instance.toString()"); // same thing +        /* +           The foo_instance has the "FooClass" type, while acceptBarInstance +           has the BarClass type.  However, since FooClass extends BarClass, it +           is accepted. +         */ +        BarClass.acceptBarInstance(foo_instance); + +        /* +           The classes below have some more advanced examples, the "example()" +           method will just run them here. +         */ +        SimpleEnumTest.example(); +        ComplexEnumTest.example(); +        TypedefsAndStructuralTypes.example(); +        UsingExample.example(); -        // instance has the "FooClass" type, while acceptBaseFoo has the -        // BaseFooClass type.  However, since FooClass extends BaseFooClass, -        // it is accepted. -        BaseFooClass.acceptBaseFoo(instance);      }  } @@ -406,7 +514,7 @@ class LearnHaxe3{  /*     This is the "child class" of the main LearnHaxe3 Class   */ -class FooClass extends BaseFooClass implements BaseFooInterface{ +class FooClass extends BarClass implements BarInterface{      public var public_any:Int; // public variables are accessible anywhere      public var public_read (default,null): Int; // use this style to only enable public read      public var public_write (null, default): Int; // or public write @@ -418,7 +526,7 @@ class FooClass extends BaseFooClass implements BaseFooInterface{      // a public constructor      public function new(arg:Int){ -        super(); // call the constructor of the parent object, since we extended BaseFooClass +        super(); // call the constructor of the parent object, since we extended BarClass          this.public_any= 0;          this._private = arg; @@ -442,7 +550,7 @@ class FooClass extends BaseFooClass implements BaseFooInterface{      }      // this class needs to have this function defined, since it implements -    // the BaseFooInterface interface. +    // the BarInterface interface.      public function baseFunction(x: Int) : String{          // convert the int to string automatically          return x + " was passed into baseFunction!"; @@ -452,21 +560,217 @@ class FooClass extends BaseFooClass implements BaseFooInterface{  /*      A simple class to extend  */ -class BaseFooClass { +class BarClass {      var base_variable:Int;      public function new(){          base_variable = 4;      } -    public static function acceptBaseFoo(b:BaseFooClass){ +    public static function acceptBarInstance(b:BarClass){      }  }  /*      A simple interface to implement  */ -interface BaseFooInterface{ +interface BarInterface{      public function baseFunction(x:Int):String;  } +////////////////////////////////////////////////////////////////// +// Enums and Switch Statements +////////////////////////////////////////////////////////////////// + +/* +   Enums in Haxe are very powerful.  In their simplest form, enums +   are a type with a limited number of states: + */ + +enum SimpleEnum { +    Foo; +    Bar; +    Baz; +} + +//   Here's a class that uses it: + +class SimpleEnumTest{ +    public static function example(){ +        var e_explicit:SimpleEnum = SimpleEnum.Foo; // you can specify the "full" name +        var e = Foo; // but inference will work as well. +        switch(e){ +            case Foo: trace("e was Foo"); +            case Bar: trace("e was Bar"); +            case Baz: trace("e was Baz"); // comment this line to throw an error. +        } + +        /* +           This doesn't seem so different from simple value switches on strings. +           However, if we don't include *all* of the states, the compiler will +           complain.  You can try it by commenting out a line above. + +           You can also specify a default for enum switches as well: +         */ +        switch(e){ +            case Foo: trace("e was Foo again"); +            default : trace("default works here too"); +        } +    } +} + +/* +    Enums go much further than simple states, we can also enumerate +    *constructors*, but we'll need a more complex enum example + */ +enum ComplexEnum{ +    IntEnum(i:Int); +    MultiEnum(i:Int, j:String, k:Float); +    SimpleEnumEnum(s:SimpleEnum); +    ComplexEnumEnum(c:ComplexEnum); +} +// Note: The enum above can include *other* enums as well, including itself! + +class ComplexEnumTest{ +    public static function example(){ +        var e1:ComplexEnum = IntEnum(4); // specifying the enum parameter +        /* +           Now we can switch on the enum, as well as extract any parameters +           it might of had. +         */ +        switch(e1){ +            case IntEnum(x) : trace('$x was the parameter passed to e1'); +            default: trace("Shouldn't be printed"); +        } + +        // another parameter here that is itself an enum... an enum enum? +        var e2 = SimpleEnumEnum(Foo); +        switch(e2){ +            case SimpleEnumEnum(s): trace('$s was the parameter passed to e2'); +            default: trace("Shouldn't be printed"); +        } + +        // enums all the way down +        var e3 = ComplexEnumEnum(ComplexEnumEnum(MultiEnum(4, 'hi', 4.3))); +        switch(e3){ +            // You can look for certain nested enums by specifying them explicitly: +            case ComplexEnumEnum(ComplexEnumEnum(MultiEnum(i,j,k))) : { +                trace('$i, $j, and $k were passed into this nested monster'); +            } +            default: trace("Shouldn't be printed"); +        } +        /* +           Check out "generalized algebraic data types" (GADT) for more details +           on why these are so great. +         */ +    } +} + +class TypedefsAndStructuralTypes { +    public static function example(){ +        /* +           Here we're going to use typedef types, instead of base types. +           At the top we've declared the type "FooString" to mean a "String" type. +         */ +        var t1:FooString = "some string"; + +        /* +           We can use typedefs for "structural types" as well.  These types are +           defined by their field structure, not by class inheritance.  Here's +           an anonymous object with a String field named "foo": +         */ + +        var anon_obj = { foo: 'hi' }; + +        /* +           The anon_obj variable doesn't have a type declared, and is an +           anonymous object according to the compiler.  However, remember back at +           the top where we declared the FooObj typedef?  Since anon_obj matches +           that structure, we can use it anywhere that a "FooObject" type is +           expected. +         */ + +        var f = function(fo:FooObject){ +            trace('$fo was passed in to this function'); +        } +        f(anon_obj); // call the FooObject signature function with anon_obj. + +        /* +           Note that typedefs can have optional fields as well, marked with "?" + +           typedef OptionalFooObj = { +                ?optionalString: String, +                requiredInt: Int +           } +         */ + +        /* +           Typedefs work well with conditional compilation.  For instance, +           we could have included this at the top of the file: + +#if( js ) +        typedef Surface = js.html.CanvasRenderingContext2D; +#elseif( nme ) +        typedef Surface = nme.display.Graphics; +#elseif( !flash9 ) +        typedef Surface = flash8.MovieClip; +#elseif( java ) +        typedef Surface = java.awt.geom.GeneralPath; +#end + +        That would give us a single "Surface" type to work with across +        all of those platforms. +        */ +    } +} + +class UsingExample { +    public static function example() { + +        /* +           The "using" import keyword is a special type of class import that +           alters the behavior of any static methods in the class. + +           In this file, we've applied "using" to "StringTools", which contains +           a number of static methods for dealing with String types. +         */ +        trace(StringTools.endsWith("foobar", "bar") + " should be true!"); + +        /* +           With a "using" import, the first argument type is extended with the +           method.  What does that mean?  Well, since "endsWith" has a first +           argument type of "String", that means all String types now have the +           "endsWith" method: +         */ +        trace("foobar".endsWith("bar") + " should be true!"); + +        /* +           This technique enables a good deal of expression for certain types, +           while limiting the scope of modifications to a single file. + +           Note that the String instance is *not* modified in the run time. +           The newly attached method is not really part of the attached +           instance, and the compiler still generates code equivalent to a +           static method. +         */ +      } + +} +  ``` +We're still only scratching the surface here of what Haxe can do.  For a formal +overiew of all Haxe features, checkout the [online +manual](http://haxe.org/manual), the [online api](http://api.haxe.org/), and +"haxelib", the [haxe library repo] (http://lib.haxe.org/). + +For more advanced topics, consider checking out: + +* [Abstract types](http://haxe.org/manual/abstracts) +* [Macros](http://haxe.org/manual/macros), and [Compiler Macros](http://haxe.org/manual/macros_compiler) +* [Tips and Tricks](http://haxe.org/manual/tips_and_tricks) + + +Finally, please join us on [the mailing list](https://groups.google.com/forum/#!forum/haxelang), on IRC [#haxe on +freenode](http://webchat.freenode.net/), or on +[Google+](https://plus.google.com/communities/103302587329918132234). + + | 
