OSDN Git Service

【更新内容】
[ring-lang-081/ring.git] / docs / en / target / oop.txt
1 .. index:: 
2         single: Object Oriented Programming; Introduction
3
4 =================================
5 Object Oriented Programming (OOP)
6 =================================
7
8 In this chapter we are going to learn how to use the Object-Oriented programming paradigm
9 inside the Ring programming language.
10
11 We will learn about
12
13 * Classes and Objects
14 * Access Objects Using Braces
15 * Composition
16 * Setter and Getter
17 * Private Attributes and Methods
18 * Operator Overloading
19 * Inheritance
20 * Dynamic Attributes
21 * Packages
22 * Printing Objects
23 * Find() and List of Objects
24 * Sort() and List of Objects
25 * Using Self.Attribute and Self.Method()
26 * Using This.Attribute and This.Method()
27
28
29 .. index:: 
30         pair: Object Oriented Programming; Classes and Objects
31
32
33 Classes and Objects
34 ===================
35
36 We can define new classes using the next syntax
37
38 Syntax:
39
40 .. code-block:: ring
41
42         Class <Class Name> [From|<|: <Parent Class Name>]
43                 [Attributes]
44                 [Methods]
45                 [Private
46                   [Attributes]
47                   [Methods]
48                 ]
49
50 And we can create objects using the next syntax
51
52 Syntax:
53
54 .. code-block:: ring
55
56         New <Object Name> [ (init method parameters) ] |
57                           [ { access object data and methods } ]   ---> Object
58
59 Example:
60
61 .. code-block:: ring
62
63         New point { x=10  y=20  z=30  print() }
64         Class Point x y z func print see x + nl + y + nl + z + nl 
65
66 .. note:: We can use { } to access object data and methods.
67
68 .. tip:: we can declare the class attributes directly after the class name.
69
70 Output:
71
72 .. code-block:: ring
73
74         10
75         20
76         30
77
78 We can rewrite the same program in another style
79
80 .. code-block:: ring
81
82         New point                       # create new object using the point class
83         {                               # access the new object attributes and methods
84                 x = 10                  # set the x attribute to 10
85                 y = 20                  # set the y attribute to 20
86                 z = 30                  # set the z attribute to 30
87                 print()                 # call the print method
88         }                               # end of object access 
89
90
91         Class Point                     # define the Point class
92                 x y z                   # the class contains three attributes x, y & z
93                 func print              # define the print method
94                         see x + nl +    # print the x attribute
95                             y + nl +    # print the y attribute
96                             z + nl      # print the z attribute
97
98
99
100 Also we can write the same program in another way
101
102 .. code-block:: ring
103
104         P1 = New Point
105         P1.x = 10
106         P1.y = 20
107         P1.z = 30
108         P1.Print()
109         Class Point x y z func print see x + nl + y + nl + z + nl       
110
111 .. note:: we can use the dot operator after the object name to access object members.
112
113 Also we can write the same program in another way
114
115 .. code-block:: ring
116
117         new point { print() }   
118         Class Point
119                 x = 10  y = 20  z = 30
120                 func print see x + nl + y + nl + z + nl
121
122 .. note:: we can set the default values for the class attributes when we declare them.
123
124 Also we can write the same program in another way
125
126 .. code-block:: ring
127
128         new point(10,20,30)
129         Class Point
130                 x y z 
131                 func init p1,p2,p3 x=p1 y=p2 z=p3 print()
132                 func print see x + nl + y + nl + z + nl
133
134 .. note:: we can call the init method directly using () when we create new objects 
135
136 Also we can write the same program in another way
137
138 .. code-block:: ring
139
140         new point( [ :x = 10 , :y = 20 , :z = 30 ] )
141         Class Point x y z
142               func init aPara x = aPara[:x] y = aPara[:y] z = aPara[:z] print()
143               func print see x + nl + y + nl + z + nl
144
145 .. tip:: using Hash for passing method parameters enable us to create optional 
146          parameters and change the order of parameters when adding them to the Hash.
147
148 .. index:: 
149         pair: Object Oriented Programming; Access Objects Using Braces
150
151 Access Objects Using Braces
152 ===========================
153
154 We can access the object at any time using braces { } 
155
156 Inside the braces we can use the object attributes and methods directly
157
158 This can be done when we create the object using the New keyword or at any time using the next syntax
159
160 .. code-block:: ring
161
162         ObjectName { access object data and methods }
163
164 Example:
165
166 .. code-block:: ring
167
168         See "Creating the Object" + nl
169         o1 = new Point
170         See "Using the Object" + nl
171         o1 {
172                 x=5     
173                 y=15
174                 z=25    
175                 print()
176         }
177         Class Point x y z func print see x + nl + y + nl + z 
178
179 We can use braces to access objects when we call functions or methods
180
181 Example:
182
183 .. code-block:: ring
184
185         o1 = new Point
186
187         print( o1 { x=10 y=20 z=30 } )
188         
189         func print object
190                 see object.x + nl + 
191                     object.y + nl + 
192                     object.z 
193
194         Class Point x y z
195
196 We can mix between using braces and the dot operator to access the object in the same expression.
197
198
199 Example:
200
201 .. code-block:: ring
202
203         o1 = new Point
204
205         O1 { x=10 y=20 z=30 }.print()
206         
207         Class Point x y z
208                 func print see x + nl + y + nl + z
209
210 .. index:: 
211         pair: Object Oriented Programming; Composition
212
213 Composition
214 ===========
215
216 The object may contains other objects as attributes.
217
218 Using braces to access objects can be nested.
219
220 Example:
221
222 .. code-block:: ring
223
224         R1 = New Rectangle 
225         {
226
227                 Name = "Rectangle 1"
228
229                 P1 
230                 {
231                         X = 10
232                         Y = 20
233                 }
234
235                 P2 
236                 {
237                         X = 200
238                         Y = 300
239                 }       
240
241                 Color = "Blue"
242
243         }
244         
245         see "Name : " + R1.Name + nl +
246             "Color: " + R1.Color + nl +
247             "P1   : (" + R1.P1.X + "," + R1.P1.Y + ")" + nl + 
248             "P2   : (" + R1.P2.X + "," + R1.P2.Y + ")"  
249
250         Class Rectangle
251                 name  color
252                 p1 = new Point
253                 p2 = new Point
254
255         Class Point x y 
256
257 Output:
258
259 .. code-block:: ring
260
261         Name : Rectangle 1
262         Color: Blue
263         P1   : (10,20)
264         P2   : (200,300)
265
266 .. index:: 
267         pair: Object Oriented Programming; Setter and Getter
268
269 Setter and Getter
270 =================
271
272 We can define methods to be used when we set and get object attributes.
273
274 Syntax:
275
276 .. code-block:: ring
277
278         Class ClassName
279
280                 AttributeName
281                 ...
282
283                 Func SetAttributeName
284                         ...
285
286                 Func GetAttributeName
287                         ...
288
289 Example:
290
291 .. code-block:: ring
292
293         o1 = new person
294
295         o1.name = "Mahmoud"  see o1.name + nl
296
297         o1 { name = "Ahmed"  see name }
298
299         Class Person
300
301                 name family = "Fayed"
302
303                 func setname value
304                         see "Message from SetName() Function!" + nl
305                         name = value + " " + family
306
307                 func getname
308                         see "Message from GetName() Function!" + nl
309                         return "Mr. " + name
310
311 Output:
312
313 .. code-block:: ring
314
315         Message from SetName() Function!
316         Message from GetName() Function!
317         Mr. Mahmoud Fayed
318         Message from SetName() Function!
319         Message from GetName() Function!
320         Mr. Ahmed Fayed
321
322 .. index:: 
323         pair: Object Oriented Programming; Private Attributes and Methods
324
325 Private Attributes and Methods
326 ==============================          
327
328 We can define private attributes and methods after the keyword private inside the class body
329
330 Example:
331
332 .. code-block:: ring
333
334         o1 = new person {
335                 name = "Test"
336                 age = 20
337                 print()
338                 o1.printsalary()
339         }
340
341         try
342                 see o1.salary
343         catch
344                 see cCatchError + nl
345         done
346
347         try
348                 o1.increasesalary(1000)
349         catch
350                 see cCatchError + nl
351         done
352
353         Class Person
354
355                 name age 
356
357                 func print
358                         see "Name   : " + name + nl + 
359                             "Age    : " + age + nl 
360
361                 func printsalary
362                         see "Salary : " + salary + nl 
363
364                 private
365
366                 salary = 15000
367
368                 func increasesalary x
369                         salary += x
370
371 Output:
372
373 .. code-block:: ring
374
375         Name   : Test
376         Age    : 20
377         Salary : 15000
378         Error (R27) : Using private attribute from outside the class : salary
379         Error (R26) : Calling private method from outside the class : increasesalary
380
381 .. index:: 
382         pair: Object Oriented Programming; Operator Overloading
383
384 Operator Overloading
385 ====================
386
387 We can add the operator method to our class to enable using operators with the class objects.
388
389 Syntax:
390
391 .. code-block:: ring
392
393         Class ClassName
394
395                 ...
396
397                 Func operator cOperator,Para
398
399                         ...
400
401 The function operator takes two paramters, the first represent the operator
402 and the second represent the second parameter after the operator.
403
404 Example:
405
406 .. code-block:: ring
407
408         o1 = new point { x = 10 y = 10 print("P1    : ") }
409         o2 = new point { x = 20 y = 40 print("P2    : ") }
410
411         o3 = o1 + o2
412         o3.print("P1+P2 : ")
413
414         class point x y
415
416                 func operator cOperator,Para
417                         result = new point      
418                         switch cOperator
419                         on "+"
420                                 result.x = x + Para.x
421                                 result.y = y + Para.y
422                         on "-"
423                                 result.x = x - Para.x
424                                 result.y = y - Para.y
425                         off
426                         return result
427
428                 func print cPoint
429                         see cPoint + "X : " + x + " Y : " + y + nl
430
431 Output:
432
433 .. code-block:: ring
434
435         P1    : X : 10 Y : 10
436         P2    : X : 20 Y : 40
437         P1+P2 : X : 30 Y : 50
438
439
440 The next example from the List class in the stdlib.ring
441
442 .. code-block:: ring
443
444         Func operator cOperator,Para
445                 result = new list
446                 switch cOperator
447                         on "+"
448                                 if isobject(para)
449                                         for t in Para.vValue
450                                                 vValue + t
451                                         next
452                                 but islist(para)
453                                         for t in Para
454                                                 vValue + t
455                                         next
456                                 ok
457                         on "len"
458                                 return len( vValue )
459                         on "[]"
460                                 return &vValue[para]
461                 off
462                 return result
463
464 The "len" operator is used with (for in) control structure.
465
466 The "[]" operator is used when we try to access the list items, In this case we use the & operator
467 to return the item values like strings an numbers by reference, so we can update it when we access the
468 items.
469
470 Another Example
471
472 .. code-block:: ring
473
474         func main 
475
476         See "----1"+nl
477             a1 = new BigNumber( "123" )
478             a2 = new BigNumber( "456" )
479             a3 = new BigNumber( "789" )
480         See nl+"----2"+nl  
481                 a1.print()
482                 a2.print()
483                 a3.print()
484         See nl+"----3"+nl      
485             a2 = a1 + "45"  
486         See nl+"----4"+nl  
487             a2.print()      
488         See nl+"----5"+nl  
489             a3 = a1 + a2    
490         See nl+"----6"+nl  
491             a3.print()      
492         See nl+"----7"+nl
493
494         ###==================================
495         Func FuncAdd( num1, num2)
496            Sum = 0 + num1 + num2    ### Para.aData isNumber
497            Sum = "" +Sum            ### Para.adata isString
498         return Sum                  ### return to Class
499         ###===================================
500
501         class BigNumber 
502
503             ### Variables
504             aData = "468"
505
506             ### Functions INIT default values
507             func init aPara 
508                 ? "INIT aPara: " ? aPara
509                 if isString(aPara)
510                     aData = aPara 
511                 else 
512                     aData = "" + aPara
513                 ok
514
515             ### Other Functions
516             func operator cOperator, Para
517                     whatType = Type(Para)
518                     ? nl+"WhatType-PARA: "+ whatType ? Para 
519                     ? nl+"Operator: " ? cOperator  ? nl+"PARA: " ? Para ? "    ______" ? nl
520                                     if whatType = "STRING"
521                                        dataInfo = Para
522                                        ? "dataInfo String: " ? dataInfo
523                                     but whatType = "NUMBER"
524                                        datinfo  = "" + Para
525                                        ? "dataInfo Number: " ? dataInfo
526                                     else whatType = "OBJECT"
527                                        dataInfo = "" + para.aData  
528                                        ? "dataInfo OBJECT: " ? dataInfo
529                                     ok
530                                   ? "dataInfo USING: " ? dataInfo  
531                     ### Para.aData does NOT exist on first pass ( Object with member)
532                     ### Result isObject when assigned "self"
533                     result = self   
534                     switch cOperator
535                         on "+"
536                              answer = FuncAdd( aData, dataInfo )
537                              ? nl+"AnswerString - FunAdd aData, dataInfo: " ? answer  
538                              ### result = self, is Object, populate Object with aData member
539                              result.aData = answer
540                         off
541                     ### Result = Self is Object
542                     return result   
543
544             func print 
545                 ? nl+"ClassPrint aData: " ? aData       
546
547 .. index:: 
548         pair: Object Oriented Programming; Inheritance
549
550 Inheritance
551 ===========
552
553 We can create class from another class in the class definition using the keyword from.
554
555 Syntax:
556
557 .. code-block:: ring
558
559         Class <Class Name> [From <Parent Class Name>]
560
561 We can call a method in the parent class from the child class using the super object.
562
563 Syntax:
564
565 .. code-block:: ring
566
567         func methodname
568                 ...
569                 super.methodname()
570                 ...
571
572 Example:
573
574 .. code-block:: ring
575
576         Func main
577                 e1 = new Employee {
578                         Name = "test"
579                         age = 20
580                         job = "programmer"
581                         salary = 20000000
582                         print()
583                 }
584         
585
586         Class Human 
587                 Name Age
588                 func print
589                         see "Name : " + name + nl + "Age  : " + age + nl
590
591         Class Employee from Human
592                 Job Salary
593                 func print
594                         super.print()
595                         see "Job  : " + job + nl + "Salary : " + salary + nl
596
597 Output:
598
599 .. code-block:: ring
600
601         Name : test
602         Age  : 20
603         Job  : programmer
604         Salary : 20000000
605
606 .. index:: 
607         pair: Object Oriented Programming; Dynamic Attributes
608
609 Dynamic Attributes
610 ==================
611
612 We can write instructions after the class name to be executed when we create new objects
613
614 Example:
615
616 .. code-block:: ring
617
618         o1 = new dynamicClass
619         see o1.var5 + nl        # output 5
620
621         Class DynamicClass
622                 for x = 1 to 10
623                         cStr = "var" + x + " = " + x
624                         eval(cStr)
625                 next
626
627 .. tip:: in the previous example var1, var2, ..., var10 will be defined as attributes.
628
629 .. tip:: The problem with the previous example is that x and cStr will be defined as attributes too!
630
631 .. note:: we can write class definitions inside a string then 
632           using eval() we can execute the string to define the classes
633
634 .. index:: 
635         pair: Object Oriented Programming; Packages
636
637 Packages
638 ========
639
640 We can create a package (a group of classes under a common name) using the next syntax
641
642 .. code-block:: ring
643
644         package PackageName
645                 Class Class1
646                         ...
647                 Class Class2
648                         ...
649                 Class Class3
650                         ...
651                 ...
652
653 Example
654
655 .. code-block:: ring
656
657         o1 = new System.output.console
658         o1.print("Hello World")
659         
660         Package System.Output
661                 Class Console
662                         Func Print cText
663                                 see cText + nl
664
665 .. note:: we can use the dot operator as part of the package name
666
667 Instead of typing the long name PackageName.ClassName we can use the import command
668
669 When we import a package, we can use any class inside this package directly.
670
671 Example
672
673 .. code-block:: ring
674
675         import system.output
676         o1 = new console {
677                 print("Hello World")
678         }
679         Package System.Output
680                 Class Console
681                         Func Print cText
682                                 see cText + nl
683
684 .. index:: 
685         pair: Object Oriented Programming; Printing Objects
686
687 Printing Objects
688 ================
689
690 We can print the object state (attributes and values) using the see command.
691
692 Example:
693
694 .. code-block:: ring
695
696         see new point { x=10 y=20 z=30 }
697         class point x y z
698
699 Output:
700
701 .. code-block:: ring
702
703         x: 10.000000
704         y: 20.000000
705         z: 30.000000
706
707 .. index:: 
708         pair: Object Oriented Programming; Find() and List of Objects
709
710 Find() and List of Objects
711 ==========================
712
713 We can use the find() function to search inside a list of objects.
714
715 Syntax:
716
717 .. code-block:: ring
718
719         Find(List,ItemValue,nColumn,cAttribute) ---> Item Index
720
721 Example:
722
723 .. code-block:: ring
724
725         myList1 = [new Company {position=3 name="Mahmoud" symbol="MHD"},
726                    new Company {position=2 name="Bert" symbol="BRT"},
727                    new Company {position=1 name="Ring" symbol="RNG"}
728                   ]
729
730         see find(mylist1,"Bert",1,"name") + nl
731         see find(mylist1,"Ring",1,"name") + nl
732         see find(mylist1,"Mahmoud",1,"name") + nl
733         see find(mylist1,"RNG",1,"symbol") + nl
734         see find(mylist1,"MHD",1,"symbol") + nl
735         see find(mylist1,"BRT",1,"symbol") + nl
736         see find(mylist1,3,1,"position") + nl
737         see find(mylist1,1,1,"position") + nl
738         see "Other" + nl
739         see find(mylist1,"test",1,"name") + nl
740         see find(mylist1,"test",0,"name") + nl
741         see find(mylist1,"test",5,"name") + nl
742
743         class company position name symbol
744
745 Output:
746
747 .. code-block:: ring
748
749         2
750         3
751         1
752         3
753         1
754         2
755         1
756         3
757         Other
758         0
759         0
760         0
761
762 .. index:: 
763         pair: Object Oriented Programming; Sort() and List of Objects
764
765 Sort() and List of Objects
766 ==========================
767
768 We can sort a list of objects based on an object attribute using the Sort() function.
769
770 Syntax:
771
772 .. code-block:: ring
773
774         Sort(List,nColumn,cAttribute) ---> Sorted List based on Object Attribute
775
776 Example:
777
778 .. code-block:: ring
779
780         myList1 = [
781                         new Company {position=3 name="Mahmoud" symbol="MHD"},
782                         new Company {position=2 name="Bert" symbol="BRT"},
783                         new Company {position=8 name="Charlie" symbol="CHR"},
784                         new Company {position=6 name="Easy" symbol="FEAS"},
785                         new Company {position=7 name="Fox" symbol="EFOX"},
786                         new Company {position=5 name="Dog" symbol="GDOG"},
787                         new Company {position=4 name="George" symbol="DGRG"},
788                         new Company {position=1 name="Ring" symbol="RNG"}
789                   ]
790
791         see sort(mylist1,1,"name")
792         see copy("*",70) + nl
793         see sort(mylist1,1,"symbol")
794         see copy("*",70) + nl
795         see sort(mylist1,1,"position")
796
797         class company position name symbol
798
799 Output:
800
801 .. code-block:: ring
802
803
804         position: 2.000000
805         name: Bert
806         symbol: BRT
807         position: 8.000000
808         name: Charlie
809         symbol: CHR
810         position: 5.000000
811         name: Dog
812         symbol: GDOG
813         position: 6.000000
814         name: Easy
815         symbol: FEAS
816         position: 7.000000
817         name: Fox
818         symbol: EFOX
819         position: 4.000000
820         name: George
821         symbol: DGRG
822         position: 3.000000
823         name: Mahmoud
824         symbol: MHD
825         position: 1.000000
826         name: Ring
827         symbol: RNG
828         **********************************************************************
829         position: 2.000000
830         name: Bert
831         symbol: BRT
832         position: 8.000000
833         name: Charlie
834         symbol: CHR
835         position: 4.000000
836         name: George
837         symbol: DGRG
838         position: 7.000000
839         name: Fox
840         symbol: EFOX
841         position: 6.000000
842         name: Easy
843         symbol: FEAS
844         position: 5.000000
845         name: Dog
846         symbol: GDOG
847         position: 3.000000
848         name: Mahmoud
849         symbol: MHD
850         position: 1.000000
851         name: Ring
852         symbol: RNG
853         **********************************************************************
854         position: 1.000000
855         name: Ring
856         symbol: RNG
857         position: 2.000000
858         name: Bert
859         symbol: BRT
860         position: 3.000000
861         name: Mahmoud
862         symbol: MHD
863         position: 4.000000
864         name: George
865         symbol: DGRG
866         position: 5.000000
867         name: Dog
868         symbol: GDOG
869         position: 6.000000
870         name: Easy
871         symbol: FEAS
872         position: 7.000000
873         name: Fox
874         symbol: EFOX
875         position: 8.000000
876         name: Charlie
877         symbol: CHR
878
879 .. index:: 
880         pair: Object Oriented Programming; Using Self.Attribute
881
882 Using Self.Attribute and Self.Method()
883 ======================================
884
885 Inside the class region (After the class name and before any method) and the class methods we can
886 use self.attribute and self.method()
887
888 .. code-block:: ring
889
890         Class Point
891                 self.x = 10
892                 self.y = 20
893                 self.z = 30
894                 func print
895                         see self.x + nl + self.y + nl + self.z + nl
896
897 .. note:: using self.attribute in the class region to define the class attribute protect the class attributes from conflict with global variables.
898
899 .. tip:: if you typed the class attributes with self.attribute and there are a global variable with the same name it will be used and the attribute will not be defined.
900
901 Check the "Scope Rules" chapter to know about the conflict between the global variable name and the attribute name
902
903 Whay this may happens?
904
905 Because 
906
907 * Because in the class region we can access global variables.
908 * Before defining any variable, Ring try to find the variable and use it if it's found.
909
910 .. note:: Try to avoid the global variables, use the main function and start their names with $ 
911
912 .. tip:: In large programs protect your classes and define their members using self.attribute
913
914 .. index:: 
915         pair: Object Oriented Programming; Using This.Attribute and This.Method()
916
917 Using This.Attribute and This.Method()
918 ======================================
919
920 Inside class methods we have access to the object scope directly. we don't need to use Self.attribute
921 or Self.method to read/write attribute and call methods.
922
923 But we can use braces {} while we are inside methods to access another object, In this case the current
924 object scope will be changed while we are inside the brace.
925
926 How we can get access to our class attributes and methods while we are inside braces?
927
928 This can be done using This.Attribute and This.Method()
929
930 Example:
931
932 .. code-block:: ring
933
934         new point  
935
936         class point 
937                 x=10 y=20 z=30
938                 print()
939                 func print
940                         new UI {
941                                 display(this.x,this.y,this.z)
942                         }
943
944         Class UI
945                 func display x,y,z
946                         see x + nl + y + nl + z + nl
947
948 .. index:: 
949         pair: Object Oriented Programming; Using This in the class region as Self
950
951 Using This in the class region as Self
952 ======================================
953
954 The class region is the region that comes after the class name and before any method.
955
956 We can use This in the class region as Self.
957
958 Example:
959
960 .. code-block:: ring
961
962         func main
963
964                 o1 = new program {
965                         test()
966                 }
967
968                 ? o1
969
970         class program 
971
972                 this.name = "My Application"
973                 this.version = "1.0"
974                 ? name ? version        
975
976                 func test
977                         ? "Name    = " + name 
978                         ? "Version = " + version
979
980 Output
981
982 .. code-block:: none
983
984         My Application
985         1.0
986         Name    = My Application
987         Version = 1.0
988         name: My Application
989         version: 1.0
990
991 .. note:: When we use braces to change the current active object, Using This we can still point to the class.
992
993 .. tip:: The difference between This and Self is that Self point to the current active object that we can change using braces.
994
995 Remember that in most cases we don't need to use This or Self in the class region
996
997 We can write
998
999
1000 .. code-block:: ring
1001
1002         class program name version
1003
1004 Or 
1005
1006 .. code-block:: ring
1007
1008         class program name="My Application" version="1.0"
1009
1010 .. note:: We use This or Self in the class region just to avoid conflict with global variables that are defined with the same name.
1011
1012
1013 .. index:: 
1014         pair: Object Oriented Programming; Default value for object attributes
1015
1016 Default value for object attributes
1017 ===================================
1018
1019 The default value for object attributes is NULL
1020
1021 In Ring, the NULL value is just an empty string or a string that contains "NULL"
1022
1023 We can check for NULL values using the isNULL() function
1024
1025 Example:
1026
1027 .. code-block:: ring
1028
1029         oProgram = new Program
1030         ? oProgram.name
1031         ? oProgram.version
1032         ? isNULL(oProgram.name)
1033         ? isNULL(oProgram.version)
1034         oProgram { name="My Application" version="1.0" }
1035         ? isNULL(oProgram.name)
1036         ? isNULL(oProgram.version)
1037         ? oProgram
1038
1039         class program
1040                 name 
1041                 version
1042
1043 Output:
1044
1045 .. code-block:: none
1046
1047         NULL
1048         NULL
1049         1
1050         1
1051         0
1052         0
1053         name: My Application
1054         version: 1.0