MN8 Tutorial
Constructors, operators and methods.
previous :: contents :: next

Back to > Overview > MN8 Tutorial

Constructors, operators and methods.

Author: Remus Pereni <remus@nolimits.ro>
Table of Contents
1. Constructors
2. Operators
3. Methods


1. Constructors

There would be no object-oriented language without constructors and naturally MN8 has them. The purpose of the constructors is quite obvious, empty concepts are not very useful and using the same sequences to fill an concept instance with data every time we want to use it is a waste of time. In order to prevent this waste of time MN8 has constructors that have the sole purpose to initialize concepts with diverse values at instantiation.

All constructors are in fact regular methods with two restrictions: the name of the method is create and have no return type.

In case a concept has no constructor(s) a default one is always created by the MN8 interpreter, one with no parameters because at every typeof the default constructor is called.

Let's see an example:

        
        #---- Person.mn8 ----
        define Person [
        	@firstName
        	@lastName 
        	address
        
        	: create ( $firstName typeof String, $lastName typeof String, $address typeof String ) [
        		@firstName = $firstName
        		@lastName = $lastName
        		/address/ = $address
        	]
        	static : main ($args typeof Series) [
        		$me = Person.create( "Remus", "Pereni", "Some address!")
        		Error.println ($me.getConceptType)
                print $me.toXML
        	]
        ]
        
By executing the Person concept will get:
        
        Person
        <Person lastName="Pereni" firstName="Remus">
        <address>Some address!</address>
        </Person>
        

There is only one weird thing in the above example, that Error.print line. Both Windows (2000, XP) and Unix flavors have two output streams an out and an err, this streams can be separated and redirected each into diverse devices. We used both streams in the example so we don't mix the XML output with a string, which would make any redirection of the result invalid XML.

We could redirect the two outputs as follows:

        
	        mn8 Person.mn8 1> res.txt 2>res.err
        
Which means that the first stream (which is the output stream) goes to res.txt file and the second stream (the error stream) goes to the res.err file.

We can have any number of constructors we like with the only restriction that should be only one constructor with the same signature. The signature of a method is a string containing the name of the method followed by the types of all it's parameters. The signature of the above constructor would be: create:String,String,String . We can use the signature also for retrieving the methods or constructors of a concept using reflection. To get the above constructor we only have to do: $me.getConceptConstructor("create:String,String,String")

If we want that a piece of code or initialization to happened any time a variable is instantiated from that type using TYPEOF we only have to override the default create constructor:

        
        #---- Person.mn8 ----
        define Person [
        	@firstName
        	@lastName
        	address
        
        	: create [
        		/address/ =  "not disclosed"
        		Error.println(" Hey I'm in the default constructor of: " + .getConceptType) 
        	]
        	static : main ( $args typeof Series ) [
        		$me typeof Person
        		print $me.toXML
        	] 	
        ]        
        
with the obvious result of:
        
        Hey I'm in the default constructor of: Person
        <Person lastName="" firstName="">
        <address>not disclosed</address>
        </Person>
        

If we would have to call another constructor in the parent class, one with parameters (like the one we declared earlier which accepts a first name, last name and address we could do that by calling instead of super.create, super.create($fName, $lName, "not disclosed").

top

2. Operators

Most MN8 concepts already have their most important operators implemented, operators like +, -, ==, <, > for concepts like Integer and String, still there will be cases where it will make a lot of sense to implement divers operators for many different custom concept types.

The operations you can define or/and override are: +, ++, +=, -, -- , -=, *, *=, /, /=, ==, !=, !, <, >, >=, <= .

Let's say we have a person concept that can have multiple emails. In case we make the email information another concept then we can define the person + email operation as an easy way to add emails to a person concept. This would look pretty much as follows:

            
        #---- EmailAddress.mn8 ----
        define EmailAddress [
            @type
            @address
        ]
        
        
        #---- Person.mn8 ----
        define Person [
        	@firstName
        	@lastName
        	emailAddresses [
        	    email* typeof EmailAddress
            ]
        
            
            :+ ( $newAddress typeof EmailAddress) [
                /emailAddresses/email.createNewEntry
                /emailAddresses/email.lastEntry@type = $newAddress@type    
                /emailAddresses/email.lastEntry@address = $newAddress@address
                return this
            ] typeof Person
        
            
        	static : main ( $args typeof Series ) [
        		$me typeof Person
        	
        		$mail1 typeof EmailAddress
        		$mail1@type = "primary"
        		$mail1@address = "remus@nolimits.ro"
        
        		$mail2 typeof EmailAddress
        		$mail2@type = "yahoo"
        		$mail2@address = "rpereni@yahoo.com"
        		
        		$me = $me + $mail1
        		$me = $me + $mail2		
        		print $me.toXML
        	] 	
        ]         
        
The result of the execution of the Person concept will be:
        
        <Person lastName="" firstName="">
        <emailAddresses>
        <email address="remus@nolimits.ro" type="primary"></email>
        <email address="rpereni@yahoo.com" type="yahoo"></email>
        </emailAddresses>
        </Person>
        

Overriding or declaring operators for new types are also very useful for example in declaring special behaviors, for instance, in determining equality. Let's say we have the good old person concept and we don't like the way MN8 does compare two instances of a person concept. We would like that two person instances to be considered as the same if the first and last name, of the two person instances, are the same regardless of the other person related information, like email address.

            
        #---- Person.mn8 ----
        define Person [
        	@firstName
        	@lastName
        	email
                
           # simple constructor to help us initialize the concept instances
            : create ( $fName typeof String, $lName typeof String, $email typeof String ) [
                @firstName = $fName
                @lastName = $lName
                /email/ = $email     
            ]
            
                   # we override the default equality operator
            : == ( $person typeof Person ) [
                
                if @firstName.toLowerCase == $person@firstName.toLowerCase and \
                   @lastName.toLowerCase == $person@lastName.toLowerCase then [
                    return true
                ]
                
                return false
            ] typeof Logical
                 
        	static : main ( $args typeof Series ) [		
                $me = Person.create( "Remus", "Pereni", "remus@nolimits.ro")
                $stillMe = Person.create("remus", "pereni", "rpereni@yahoo.com")
                $sorin = Person.create("Sorin", "Iluti", "sorin@nolimits.ro")
                
                print $me == $stillMe		
        	 	print $me == $sorin
        	]
        ]
        
By executing this concept we will get as result:
        
        true
        false
        

If you look in the equal operator overloading method, at the first if the line ends after the and with an backslash (\), because end of lines are important, when we have a long line and don't want to get to far to the right we can use the backslash operator to signalize to the MN8 interpreter that the next line is a continuation of the current line.

top

3. Methods

The synopsis of an MN8 method is:

        
(STATIC)? : method_name (( $param1Name TYPEOF Param1Type, $param2Name TYPEOF  Param2Type, … )  )? [ eol
        	## method body
        ] (TYPEOF ReturnType)? eol        
        
Really simple, isn't it?

To clear any confusion let's see another Person example in which we use some methods.

            
        #---- Person.mn8 ----
        define Person [
        	@firstName 
        	@lastName
        	birthDates [
        		@birthYear typeof Integer
        		@birthMonth typeof Integer
        		@birthDay
        	]
            
        	: getAge [
        		return Integer.create(Date.getToday.getDate("yyyy")) - /birthDates@birthYear
        	] typeof Integer
        
            static : homePageLastUpdated( $url typeof String, $justForFun typeof String) [
                $page from $url
                if $page.getHeaders.containsKey("Date") then [
                    print "Home page last updated: " + $page.getHeaders.getValue("Date")    
                ] 
            ]
           
        	static : main ($args typeof Series) [
        		$me typeof Person
        		$me/birthDates@birthYear = 1974
        		print "Age: " + $me.getAge
        		
        		Person.homePageLastUpdated("http://neuro.nolimits.ro", "xxx")
        	]
        ]
        

Executing the above concept you we'll get probably a completely different result that the one I've got and presented now, but still I think the example made the point.

The result:

        Age: 28
        Home page last updated: Tue, 22 Oct 2002 21:23:26 GMT        
        

In the above example you could see two methods getAge and homePageLastUpdated, one static the other not, one returning a value and finally one with parameters and the other without.

top


© 2001