summaryrefslogtreecommitdiffhomepage
path: root/haxe.html.markdown
blob: 60f374d81c5611bf5708f4f300d0306784b1a75c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
---
language: haxe
filename: LearnHaxe3.hx
contributors:
    - ["Justin Donaldson", "https://github.com/jdonaldson/"]
---

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.

```haxe
/*
   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
 */

// Let's start with comments... this is a single line comment

/*
   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.
 */

/*
   A package declaration isn't necessary, but it's useful if you want to
   organize your code into modules later on.  Also worth mentioning, if you use
   more than one expression in a code block, it must end in a semicolon:
 */
package; // empty package, no namespace.


// if you import code from other files, it must be declared before the rest of
// the code.
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.
using StringTools;

// Haxe files typically define classes, although they can also define other
// types of code... more on that later.


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
            );


        /*
           Remember what I said about expressions needing semicolons? You
           can put more than one expression on a line if you want.
         */
        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");

        var x = 1;
        var an_interpolated_string = 'the value of x is $x';

        /*
           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");

        /*
           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 many 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 / 4) + " 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");

        //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");

        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 (i > 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 m)");
        }


        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 _   : "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
        //////////////////////////////////////////////////////////////////

        // 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.




        //////////////////////////////////////////////////////////////////
        // 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);

        // read the public variable normally
        trace(instance.public_any + " is the value for instance.public_any");

        // we can read this variable
        trace(instance.public_read + " is the value for 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.

        trace(instance + " is the value for instance"); // calls the toString method
        trace(instance.toString() + " is the value for instance.toString()"); // same thing


        /*
           Instance has the "FooClass" type, while acceptBaseFoo has the
           BaseFooClass type.  However, since FooClass extends BaseFooClass,
           it is accepted.
         */
        BaseFooClass.acceptBaseFoo(instance);
    }

}

/*
   This is the "child class" of the main LearnHaxe3 Class
 */
class FooClass extends BaseFooClass implements BaseFooInterface{
    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
    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){
        super(); // call the constructor of the parent object, since we extended BaseFooClass

        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 BaseFooInterface 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 BaseFooClass {
    var base_variable:Int;
    public function new(){
        base_variable = 4;
    }
    public static function acceptBaseFoo(b:BaseFooClass){
    }
}

/*
    A simple interface to implement
*/
interface BaseFooInterface{
    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.
 */


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");
        }

        var e2 = SimpleEnumEnum(Foo); // another parameter here that is itself an enum... an enum enum?
        switch(e2){
            case SimpleEnumEnum(s): trace('$s was the parameter passed to e2');
            default: trace("Shouldn't be printed");
        }

        var e3 = ComplexEnumEnum(ComplexEnumEnum(MultiEnum(4, 'hi', 4.3))); // enums all the way down
        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.
         */
    }
}

```