diff options
Diffstat (limited to 'haxe.html.markdown')
-rw-r--r-- | haxe.html.markdown | 788 |
1 files changed, 788 insertions, 0 deletions
diff --git a/haxe.html.markdown b/haxe.html.markdown new file mode 100644 index 00000000..ee214540 --- /dev/null +++ b/haxe.html.markdown @@ -0,0 +1,788 @@ +--- +language: haxe +filename: LearnHaxe3.hx +contributors: + - ["Justin Donaldson", "https://github.com/jdonaldson/"] + - ["Dan Korostelev", "https://github.com/nadako/"] +--- + +Haxe is a web-oriented language that provides platform support for C++, C#, +Swf/ActionScript, Javascript, Java, and Neko byte code (also written by the +Haxe author). Note that this guide is for Haxe version 3. Some of the guide +may be applicable to older versions, but it is recommended to use other +references. + +```csharp +/* + 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 + + 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. + + */ + +// Double slashes like this will give a single-line comment + + +/* + 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.yourapp.ClassName). + + Omitting package declaration is the same as declaring an empty package. + */ +package; // empty package, no namespace. + +/* + Packages are directories that contain modules. Each module is a .hx file + that contains types defined in a package. Package names (e.g. org.yourapp) + must be lower case while module names are capitalized. A module contain one + or more types whose names are also capitalized. + + E.g, the class "org.yourapp.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 import static fields +import Lambda.array; + +// you can also use "*" to import all static fields +import Math.*; + +/* + 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; + +/* + 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 + a static main function, and specify the class in the compiler arguments. + In this case, we've specified the "LearnHaxe3" class in the compiler + arguments above. + */ + static function main(){ + + /* + Trace is the default method of printing haxe expressions to the + screen. Different targets will have different methods of + accomplishing this. E.g., java, c++, c#, etc. will print to std + out. Javascript will print to console.log, and flash will print to + an embedded TextField. All traces come with a default newline. + Finally, It's possible to prevent traces from showing by using the + "--no-traces" argument on the compiler. + */ + trace("Hello World, with trace()!"); + + /* + Trace can handle any type of value or object. It will try to print + 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); + + /* + 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'); + + + ////////////////////////////////////////////////////////////////// + // Types & Variables + ////////////////////////////////////////////////////////////////// + trace("***Types & Variables***"); + + /* + 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"); + + + /* + Haxe is statically typed, so "an_integer" is declared to have an + "Int" type, and the rest of the expression assigns the value "1" to + it. It's not necessary to declare the type in many cases. Here, + 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"); + + // The $type() method prints the type that the compiler assigns: + $type(another_integer); + + // You can also represent integers with hexadecimal: + var hex_integer = 0xffffff; + + /* + Haxe uses platform precision for Int and Float sizes. It also + uses the platform behavior for overflow. + (Other numeric types and behavior are possible using special + libraries) + */ + + /* + In addition to simple values like Integers, Floats, and Booleans, + Haxe provides standard library implementations for common data + structures like strings, arrays, lists, and maps: + */ + + 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 + parts or all of the string. + (See also the StringBuf class). + */ + var a_sub_string = a_string.substr(0,4); + 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. + */ + var re = ~/foobar/; + trace(re.match('foo') + " is the value for (~/foobar/.match('foo')))"); + + /* + Arrays are zero-indexed, dynamic, and mutable. Missing values are + defined as null. + */ + var a = new Array<String>(); // an array that contains Strings + a[0] = 'foo'; + trace(a.length + " is the value for a.length"); + a[9] = 'bar'; + trace(a.length + " is the value for a.length (after modification)"); + trace(a[3] + " is the value for a[3]"); //null + + /* + Arrays are *generic*, so you can indicate which values they contain + with a type parameter: + */ + var a2 = new Array<Int>(); // an array of Ints + var a3 = new Array<Array<String>>(); // an Array of Arrays (of Strings). + + /* + Maps are simple key/value data structures. The key and the value + can be of any type. + */ + var m = new Map<String, Int>(); // The keys are strings, the values are Ints. + m.set('foo', 4); + // You can also use array notation; + m['bar'] = 5; + trace(m.exists('bar') + " is the value for m.exists('bar')"); + trace(m.get('bar') + " is the value for m.get('bar')"); + trace(m['bar'] + " is the value for m['bar']"); + + var m2 = ['foo' => 4, 'baz' => 6]; // Alternative map syntax + trace(m2 + " is the value for m2"); + + /* + Remember, you can use type inference. The Haxe compiler will + decide the type of the variable the first time you pass an + argument that sets a type parameter. + */ + var m3 = new Map(); + m3.set(6, 'baz'); // m3 is now a Map<Int,String> + trace(m3 + " is the value for m3"); + + /* + Haxe has some more common datastructures in the haxe.ds module, such as + List, Stack, and BalancedTree + */ + + + ////////////////////////////////////////////////////////////////// + // Operators + ////////////////////////////////////////////////////////////////// + trace("***OPERATORS***"); + + // basic arithmetic + trace((4 + 3) + " is the value for (4 + 3)"); + trace((5 - 1) + " is the value for (5 - 1)"); + trace((2 * 4) + " is the value for (2 * 4)"); + trace((8 / 3) + " is the value for (8 / 3) (division always produces Floats)"); + trace((12 % 4) + " is the value for (12 % 4)"); + + + //basic comparison + trace((3 == 2) + " is the value for 3 == 2"); + trace((3 != 2) + " is the value for 3 != 2"); + trace((3 > 2) + " is the value for 3 > 2"); + trace((3 < 2) + " is the value for 3 < 2"); + trace((3 >= 2) + " is the value for 3 >= 2"); + trace((3 <= 2) + " is the value for 3 <= 2"); + + // standard bitwise operators + /* + ~ Unary bitwise complement + << Signed left shift + >> Signed right shift + >>> Unsigned right shift + & Bitwise AND + ^ Bitwise exclusive OR + | Bitwise inclusive OR + */ + + //increments + var i = 0; + trace("Increments and decrements"); + trace(i++); //i = 1. Post-Incrementation + trace(++i); //i = 2. Pre-Incrementation + trace(i--); //i = 1. Post-Decrementation + trace(--i); //i = 0. Pre-Decrementation + + ////////////////////////////////////////////////////////////////// + // Control Structures + ////////////////////////////////////////////////////////////////// + trace("***CONTROL STRUCTURES***"); + + // if statements + var j = 10; + if (j == 10){ + trace("this is printed"); + } else if (j > 10){ + trace("not greater than 10, so not printed"); + } else { + 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 + var k = 0; + while(k < 100){ + // trace(counter); // will print out numbers 0-99 + k++; + } + + // do-while loop + var l = 0; + do{ + trace("do statement always runs at least once"); + } while (l > 0); + + // for loop + /* + There is no c-style for loop in Haxe, because they are prone + to error, and not necessary. Instead, Haxe has a much simpler + and safer version that uses Iterators (more on those later). + */ + var m = [1,2,3]; + for (val in m){ + trace(val + " is the value for val in the m array"); + } + + // Note that you can iterate on an index using a range + // (more on ranges later as well) + var n = ['foo', 'bar', 'baz']; + for (val in 0...n.length){ + trace(val + " is the value for val (an index for n)"); + } + + + trace("Array Comprehensions"); + + // Array comprehensions give you the ability to iterate over arrays + // while also creating filters and modifications. + var filtered_n = [for (val in n) if (val != "foo") val]; + trace(filtered_n + " is the value for filtered_n"); + + var modified_n = [for (val in n) val += '!']; + trace(modified_n + " is the value for modified_n"); + + var filtered_and_modified_n = [for (val in n) if (val != "foo") val += "!"]; + trace(filtered_and_modified_n + " is the value for filtered_and_modified_n"); + + ////////////////////////////////////////////////////////////////// + // Switch Statements (Value Type) + ////////////////////////////////////////////////////////////////// + trace("***SWITCH STATEMENTS (VALUE TYPES)***"); + + /* + Switch statements in Haxe are very powerful. In addition to working + on basic values like strings and ints, they can also work on the + 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 = ""; + switch(my_dog_name){ + case "fido" : favorite_thing = "bone"; + case "rex" : favorite_thing = "shoe"; + case "spot" : favorite_thing = "tennis ball"; + default : favorite_thing = "some unknown treat"; + // case _ : favorite_thing = "some unknown treat"; // same as default + } + // The "_" case above is a "wildcard" value + // that will match anything. + + trace("My dog's name is" + my_dog_name + + ", and his favorite thing is a: " + + favorite_thing); + + ////////////////////////////////////////////////////////////////// + // Expression Statements + ////////////////////////////////////////////////////////////////// + trace("***EXPRESSION STATEMENTS***"); + + /* + Haxe control statements are very powerful because every statement + is also an expression, consider: + */ + + // if statements + var k = if (true) 10 else 20; + + trace("k equals ", k); // outputs 10 + + var other_favorite_thing = switch(my_dog_name) { + case "fido" : "teddy"; + case "rex" : "stick"; + case "spot" : "football"; + default : "some unknown treat"; + } + + trace("My dog's name is" + my_dog_name + + ", and his other favorite thing is a: " + + other_favorite_thing); + + ////////////////////////////////////////////////////////////////// + // Converting Value Types + ////////////////////////////////////////////////////////////////// + trace("***CONVERTING VALUE TYPES***"); + + // You can convert strings to ints fairly easily. + + // string to integer + Std.parseInt("0"); // returns 0 + Std.parseFloat("0.4"); // returns 0.4; + + // integer to string + Std.string(0); // returns "0"; + // concatenation with strings will auto-convert to string. + 0 + ""; // returns "0"; + 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 foo_instance = new FooClass(3); + + // read the public variable normally + trace(foo_instance.public_any + " is the value for foo_instance.public_any"); + + // we can read this variable + trace(foo_instance.public_read + " is the value for foo_instance.public_read"); + // but not write it + // foo_instance.public_read = 4; // this will throw an error if uncommented: + // trace(foo_instance.public_write); // as will this. + + // calls the toString method: + trace(foo_instance + " is the value for foo_instance"); + // same thing: + trace(foo_instance.toString() + " is the value for foo_instance.toString()"); + + + /* + 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(); + + } + +} + +/* + This is the "child class" of the main LearnHaxe3 Class + */ +class FooClass extends BarClass implements BarInterface{ + public var public_any:Int; // public variables are accessible anywhere + public var public_read (default, null): Int; // enable only public read + public var public_write (null, default): Int; // or only public write + public var property (get, set): Int; // use this style to enable getters/setters + + // private variables are not available outside the class. + // see @:allow for ways around this. + var _private:Int; // variables are private if they are not marked public + + // a public constructor + public function new(arg:Int){ + // call the constructor of the parent object, since we extended BarClass: + super(); + + this.public_any = 0; + this._private = arg; + + } + + // getter for _private + function get_property() : Int { + return _private; + } + + // setter for _private + function set_property(val:Int) : Int { + _private = val; + return val; + } + + // special function that is called whenever an instance is cast to a string. + public function toString(){ + return _private + " with toString() method!"; + } + + // this class needs to have this function defined, since it implements + // the BarInterface interface. + public function baseFunction(x: Int) : String{ + // convert the int to string automatically + return x + " was passed into baseFunction!"; + } +} + +/* + A simple class to extend +*/ +class BarClass { + var base_variable:Int; + public function new(){ + base_variable = 4; + } + public static function acceptBarInstance(b:BarClass){ + } +} + +/* + A simple interface to implement +*/ +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! +// Note: This is what's called *Algebraic data type* in some other languages. + +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). + + |