seed7-users Mailing List for Seed7 (Page 10)
Interpreter and compiler for the Seed7 programming language.
Brought to you by:
thomas_mertes
You can subscribe to this list here.
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2008 |
Jan
|
Feb
(9) |
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
(4) |
Aug
|
Sep
(4) |
Oct
(4) |
Nov
|
Dec
(1) |
2011 |
Jan
(2) |
Feb
|
Mar
(8) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2012 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
|
Jun
|
Jul
(2) |
Aug
(6) |
Sep
(7) |
Oct
(3) |
Nov
(10) |
Dec
(4) |
2013 |
Jan
(2) |
Feb
|
Mar
(2) |
Apr
|
May
(1) |
Jun
(2) |
Jul
|
Aug
|
Sep
|
Oct
(5) |
Nov
|
Dec
(1) |
2014 |
Jan
(1) |
Feb
|
Mar
|
Apr
(1) |
May
(6) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(4) |
Nov
(1) |
Dec
(1) |
2015 |
Jan
(2) |
Feb
(2) |
Mar
(2) |
Apr
|
May
(3) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(3) |
Dec
|
2016 |
Jan
|
Feb
(3) |
Mar
(2) |
Apr
|
May
(3) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2017 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2019 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(2) |
Jun
|
Jul
|
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
|
2020 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(3) |
Dec
(3) |
2021 |
Jan
(2) |
Feb
(6) |
Mar
(1) |
Apr
(1) |
May
(1) |
Jun
(2) |
Jul
|
Aug
(1) |
Sep
(12) |
Oct
(4) |
Nov
(17) |
Dec
(3) |
2022 |
Jan
(1) |
Feb
(2) |
Mar
|
Apr
(2) |
May
|
Jun
(17) |
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2023 |
Jan
|
Feb
(1) |
Mar
(4) |
Apr
|
May
|
Jun
(3) |
Jul
|
Aug
(1) |
Sep
(1) |
Oct
(1) |
Nov
|
Dec
|
2024 |
Jan
|
Feb
(5) |
Mar
(7) |
Apr
|
May
|
Jun
|
Jul
(4) |
Aug
(12) |
Sep
|
Oct
|
Nov
|
Dec
(2) |
2025 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Frank S. <fsw...@gm...> - 2008-07-05 04:55:58
|
Hi. I thought you might be interested that I have been successful in building seed7 with Mac OS X 10.5.4. The only special requirements appear to me that the Developer Tools must be installed (fairly obvious!) and the LIBRARY_PATH environment variable must include /usr/X11R6/lib in order to pick up the X11 library modules. Just thought I'd mention it in case anyone is interested. I did get a lot of warnings during make, but no show stoppers that I can see. I've attached the output. Frank Swarbrick fsw...@gm... |
From: Thomas M. <tho...@gm...> - 2008-05-23 16:10:11
|
Hello, I am writing a chapter about symbol scanning functions. It would be nice to get some feedback about it before the final release. Here is it: 8.7 Scanning a file The I/O concept introduced in the previous chapters separates the input of data from it's conversion. The 'read', 'readln', 'getwd' and 'getln' functions are designed to read whitespace separated data elements. When the data elements are not separated by whitespace characters this I/O concept is not possible. Instead the functions which read from the file need some knowledge about the type which they intend to read. Fortunately this is a well researched area. The lexical scanners used by compilers solve exactly this problem. Lexical scanners read symbols from a file and use the concept of a current character. A symbol can be a name, a number, a string, an operator, a parenthesis or something else. The current character is the first character to be processed when scanning a symbol. After a scanner has read a symbol the current character contains the character just after the symbol. This character could be the first character of the next symbol or some whitespace character. If the set of symbols is choosen wisely all decisions about the type of the symbol and when to stop reading characters for a symbol can be done based on the current character. Every 'file' contains a 'bufferChar' variable which is used as current character by the scanner functions defined in the "scanfile.s7i" library. The "scanfile.s7i" library contains skip... and get... functions. The skip... procedures return void and are used to skip input while the get... functions return the string of characters they have read. The following basic scanner functions are defined in the "scanfile.s7i" library: skipComment Skips a possibly nested comment from a 'file'. getComment Reads a possibly nested comment from a 'file'. skipLineComment Skips a line comment from a 'file'. getLineComment Reads a line comment from a 'file'. getDigits Reads a sequence of digits from a 'file'. getNumber Reads a numeric literal from a 'file'. getCharLiteral Reads a character literal from a 'file'. getStringLiteral Reads a string literal from a 'file'. getName Reads an alphanumeric name from a 'file'. Contrary to 'read' and 'getwd' basic scanner functions do not skip leading whitespace characters. To skip whitespace characters one of the following functions can be used: skipSpace Skips space characters from a 'file'. skipWhiteSpace Skips whitespace characters from a 'file'. getWhiteSpace Reads whitespace characters from a 'file'. skipLine Skips a line from a 'file'. getLine Reads a line from a 'file'. The advanced scanner functions do skip whitespace characters before reading a symbol: getSymbolOrComment Reads a symbol or a comment from a 'file'. getSymbol Reads a symbol from a 'file'. getHtmlTagSymbolOrComment Reads a HTML tag, a symbol or a comment from a 'file'. getHtmlTagOrContent Reads a HTML tag or the HTML content text from a 'file'. getSimpleSymbol Reads a simple symbol from a 'file'. All scanner functions assume that the first character to be processed is in 'bufferChar' and after they are finished the next character which should be processed is also in 'bufferChar'. To use scanner functions for a new opened file it is necessary to assign the first character to the 'bufferChar' with: myFile.bufferChar := getc(myFile); In most cases whole files are either processed with normal I/O functions or with scanner functions. When normal I/O functions need to be combined with scanner functions care has to be taken: - When the last function which read from a file was one of 'read', 'readln', 'getwd' or 'getln' the 'bufferChar' already contains the character which should be processed next and therefore subsequent scanner functions can be used. - Other I/O functions like 'getc' and 'gets' do not assign something to 'bufferChar'. In this case something should be assigned to 'bufferChar'. - Switching back from scanner functions to normal I/O functions is best done when the content of 'bufferChar' is known. For example at the end of the line. Scanner functions are helpful when it is necessary to read numeric input without failing when no digits are present: skipWhiteSpace(IN); if eoln(IN) then writeln("empty input"); elsif IN.bufferChar in {'0' .. '9'} then number := integer parse getDigits(IN); skipLine(IN); writeln("number " <& number); else stri := getLine(IN); writeln("command " <& literal(stri)); end if; The function 'getSymbol' is designed to read Seed7 symbols. When it returns "" the end of the file is reached. The following loop can be used to process the symbols of a Seed7 program: inFile.bufferChar := getc(inFile); currSymbol := getSymbol(inFile); while currSymbol <> "" do ... process currSymbol ... currSymbol := getSymbol(inFile); end while; Whitespace and comments are automatically skipped with the function 'getSymbol'. When comments should also be returned the function 'getSymbolOrComment' can be used. Together with the function 'getWhiteSpace' it is even possible to get the whitespace between the symbols: const func string: processFile (in string: fileName) is func result var string: result is ""; local var file: inFile is STD_NULL; var string: currSymbol is ""; begin inFile := open(fileName, "r"); if inFile <> STD_NULL then inFile.bufferChar := getc(inFile); result := getWhiteSpace(inFile); currSymbol := getSymbolOrComment(inFile); while currSymbol <> "" do result &:= currSymbol; result &:= getWhiteSpace(inFile); currSymbol := getSymbolOrComment(inFile); end while; end if; end func; In the example above the function 'processFile' gathers all symbols, whitespace and comments in the string it returns. The string returned by 'processFile' is equivalent to the one returned by the function 'getf'. That way it is easy to test the scanner functionality. The logic with 'getWhiteSpace' and 'getSymbolOrComment' can be used to add HTML tags to comments and literals. The following function colors comments with green, string and char literals with maroon and numeric literals with purple: const proc: sourceToHtml (inout file: inFile, inout file: outFile) is func local var string: currSymbol is ""; begin inFile.bufferChar := getc(inFile); write(outFile, "<pre>\n"); write(outFile, getWhiteSpace(inFile)); currSymbol := getSymbolOrComment(inFile); while currSymbol <> "" do currSymbol := replace(currSymbol, "&", "&amp;"); currSymbol := replace(currSymbol, "<", "&lt;"); if currSymbol[1] in {'"', '''} then write(outFile, "<font color=\"maroon\">"); write(outFile, currSymbol); write(outFile, "</font>"); elsif currSymbol[1] = '#' or startsWith(currSymbol, "(*") then write(outFile, "<font color=\"green\">"); write(outFile, currSymbol); write(outFile, "</font>"); elsif currSymbol[1] in digit_char then write(outFile, "<font color=\"purple\">"); write(outFile, currSymbol); write(outFile, "</font>"); else write(outFile, currSymbol); end if; write(outFile, getWhiteSpace(inFile)); currSymbol := getSymbolOrComment(inFile); end while; write(outFile, "</pre>\n"); end func; The functions 'skipSpace' and 'skipWhiteSpace' are defined in the "scanfile.s7i" library as follows: const proc: skipSpace (inout file: inFile) is func local var char: ch is ' '; begin ch := inFile.bufferChar; while ch = ' ' do ch := getc(inFile); end while; inFile.bufferChar := ch; end func; const proc: skipWhiteSpace (inout file: inFile) is func begin while inFile.bufferChar in white_space_char do inFile.bufferChar := getc(inFile); end while; end func; The functions 'skipComment' and 'skipLineComment', which can be used to skip Seed7 comments, are defined as follows: const proc: skipComment (inout file: inFile) is func local var char: character is ' '; begin character := getc(inFile); repeat repeat while character not in special_comment_char do character := getc(inFile); end while; if character = '(' then character := getc(inFile); if character = '*' then skipComment(inFile); character := getc(inFile); end if; end if; until character = '*' or character = EOF; if character <> EOF then character := getc(inFile); end if; until character = ')' or character = EOF; if character = EOF then inFile.bufferChar := EOF; else inFile.bufferChar := getc(inFile); end if; end func; # skipComment const proc: skipLineComment (inout file: inFile) is func local var char: character is ' '; begin repeat character := getc(inFile); until character = '\n' or character = EOF; inFile.bufferChar := character; end func; # skipLineComment ================================ Thanks in advance for your effort. Greetings Thomas Mertes Seed7 Homepage: http://seed7.sourceforge.net Seed7 - The extensible programming language: User defined statements and operators, abstract data types, templates without special syntax, OO with interfaces and multiple dispatch, statically typed, interpreted or compiled, portable, runs under linux/unix/windows. -- Super-Acktion nur in der GMX Spieleflat: 10 Tage für 1 Euro. Über 180 Spiele downloaden und spiele: http://flat.games.gmx.de |
From: Thomas M. <tho...@gm...> - 2008-02-15 17:52:38
|
Hello, I forgot to mention that I changed also the chapter about parameters: Since for array types (and also for struct types) 'in' parameters are defined to act as 'ref' parameters both definitions are equal. When possible 'in' parameters should be preferred over 'ref' parameters. I was not aware that the manual did not contain the information that 'in' parameters of struct types are by reference. May be I should add a table with information about types or add the nature of 'in' parameters to the various type descriptions. I will add the new chapter and the above change to the manual with the next release. Btw.: The Email Archive for seed7-users at http://sourceforge.net/mailarchive/forum.php?forum_name=seed7-users does not mention the thread about "Preview chapter about object orientation" in the "Ultimate" view. Maybe, this has to do with the fact that two mails have used this topic. Maybe this mail solves the problem. Greetings Thomas Mertes Seed7 Homepage: http://seed7.sourceforge.net Seed7 - The extensible programming language: User defined statements and operators, abstract data types, templates without special syntax, OO with interfaces and multiple dispatch. -- GMX FreeMail: 1 GB Postfach, 5 E-Mail-Adressen, 10 Free SMS. Alle Infos und kostenlose Anmeldung: http://www.gmx.net/de/go/freemail |
From: Thomas M. <tho...@gm...> - 2008-02-15 12:12:16
|
Hello, I have improved my chapter about object orientation. Many thanks to all who made suggestions. It would be nice to get some feedback about the new version before the final release. Here is it: 7. OBJECT ORIENTATION ===================== Many people will be familiar with object-orientation from languages like C++, Smalltalk, and Java. Seed7 follows the route of declaring "interfaces". An interface is a common set of operations supported by an object. For instance cars, motorcycles, lorries and vans can all accelerate or brake, if they are legal to drive on the road they can all indicate right and left. This view isn't new. C provides a primitive form of interfacing. When you write to a 'file' in C you use the same interface ('fprintf') for harddisk files, console output and printer output. The implementation does totally different things for this files. UNIX has used the "everything is a file" philosopy for ages (even network communication uses the file' interface (see sockets)). For short: An interface defines which methods are supported while the implementation describes how this is done. Several types with different method implementations can share the same interface. 7.1 Interface and implementation Seed7 uses interface types and implementation types. Objects declared with an interface type refer to a value which has an implementation type. The interface type of an object can always be determined at compile-time. Several implementation types can belong to one interface type (they implement the interface type). E.g.: The types 'null_file', 'external_file' and 'socket' implement the 'file' interface. An interface object can only refer to a value with an implementation type that implements the interface. E.g.: A 'shape' variable cannot refer to a 'socket'. A new interface type is declared with: const type: shape is new interface; Interface (DYNAMIC) functions describe what can be done with objects of an interface type. An interface function for a 'shape' could be: const proc: draw (in shape param, inout window param) is DYNAMIC; Now we know that it is possible to 'draw' a 'shape' to a 'window'. How this drawing is done is described in the implementation type. An implementation type for 'shape' is: const type: circle is new struct var integer: radius is 0; end struct; The fact that the type 'circle' is an implementation type of 'shape' is described with: type_implements_interface(circle, shape); The function which implements 'draw' for 'circle's is: const proc: draw (in circle: aCircle, inout window: aWindow) is func begin circle(aWindow.win, aWindow.currX, aWindow.currY, aCircle.radius, aWindow.foreground); end func; In the classic OOP philosopy a message is sent to an object. In the method the receiving object is referred with 'self' or 'this'. The other parameters use the same mechanisms as in procedural programming languages (value or reference parameter). Seed7 uses a different approach: All parameters get a user defined name. In the above example the name 'aCircle' was used for the 'self'/'this' parameter. A function to create new circle objects can also be helpful: const func circle: circle (in integer: radius) is func result var circle: result is circle.value; begin result.radius := radius; end func; Now we can draw a 'circle' object with: draw(circle(50), aWindow); Although the statement above does exactly what it should do and the separation between interface and implementation is obvious, most OO enthusiasts would not be thrilled. All decisions which implementation function should be called can be made at compile time. To please the OO fans such decisions must be made at runtime. This decision process is called dynamic dispatch. 7.2 Dynamic dispatch When the implementation types have different implementations of the same function (method) a dynamic dispatch is necessary. The type of the value, refered by an interface object, is not known at compile-time. In this case the program must decide at runtime which implementation of the function should be invoked. This decision is based on the type of the value of an object. A dynamic dispatch only takes place when a DYNAMIC (or interface) function is called. When the program is analyzed (in the interpreter or compiler) the interface functions take precedence over normal functions when both are to be considered. To demonstrate the dynamic dispatch we define the type 'line' which also implements a 'shape': const type: line is new struct var integer: xLen is 0.0; var integer: yLen is 0.0; end func; type_implements_interface(line, shape); const proc: draw (in line: aLine, in window: aWindow) is func begin line(aWindow.win, aWindow.currX, aWindow.currY, aLine.xLen, aLine.yLen, aWindow.foreground); end func; const func line: line (in integer: xLen, in integer: yLen) is func result var line: result is line.value; begin result.xLen := xLen; result.yLen := yLen; end func; In addition we define a normal (not DYNAMIC) function which draws 'shape's to the 'currWindow': const proc: draw (in shape: aShape) is func begin draw(aShape, currWindow); end func; In the example above the call of the (DYNAMIC) interface function is 'draw(aShape, currWindow)'. The interface function declared with const proc: draw (in shape param, inout window param) is DYNAMIC; decides which implementation function has to be called. The dynamic dispatch works as follows: - For all parameters which have an interface type the parameter is replaced with its value. In this case the parameter 'aShape' is replaced by a value of type 'circle' or 'line'. - The same logic as in the analyze part of the compiler is used to find the matching function. In this search normal functions take precedence over interface functions. - When a matching function is found it is called. This process describes the principal logic of the dynamic dispatch. In practice it is not necessary to execute the analyze part of the compiler during the runtime. It is possible to simplify this process with tables and function pointers. 7.3 Inheritance When a new 'struct' type is defined it is possible to inherit from an existing 'struct' type. E.g.: const type: external_file is sub null_file struct var PRIMITIVE_FILE: ext_file is PRIMITIVE_NULL_FILE; var string: name is ""; end struct; That way the type 'external_file' inherits the fields and methods of 'null_file', which is declared as: const type: null_file is new struct var char: bufferChar is '\n'; var boolean: io_empty is FALSE; var boolean: io_ok is TRUE; end struct; In most situations it makes sense when the implementation types inherit from a basic implementation type such as 'null_file'. That way it is possible to define functions which are inherited by all derived implementation types. In the standard library the function 'getln' is such a function: const func string: getln (inout null_file: aFile) is func result var string: stri is ""; local var string: buffer is ""; begin buffer := gets(aFile, 1); while buffer <> "\n" and buffer <> "" do stri &:= buffer; buffer := gets(aFile, 1); end while; aFile.bufferChar := buffer[1]; end func; All inherited types of 'null_file' inherit the function 'getln', but they are also free to redeclare it. In the 'getln' function above the function call 'gets(aFile, 1)' uses the (DYNAMIC) interface function: const func string: gets (inout file param, in integer param) is DYNAMIC; In other OO languages the distinction between interface type and basic implementation type is not done. Such languages either use a dynamic dispatch for every method call (as Java does) or need a keyword to request a dynamic dispatch (as C++ does with the 'virtual' keyword). When assignments take place between inherited implementation types it is important to note that structure assignments are done with (deep) copies. Naturally such assignments can only copy the elements that are present in both structures. In the following example just the 'null_file' elements are copied from 'anExternalFile' to 'aNullFile': const proc: example is func local var null_file: aNullFile is null_file.value; var external_file: anExternalFile is external_file.value; begin aNullFile := anExternalFile; write(aNullFile, "hello"); end func; Although the variable 'anExternalFile' is assigned to 'aNullFile', the statement 'write(aNullFile, "hello")' calls the 'write' function (method) of the type 'null_file'. A new interface type can also inherit from an existing interface type: const type: shape is sub object interface; Although inheritance is a very powerful feature it should be used with care. In many situations it makes more sense that a new type has an element of another type (so called has-a relation) instead of inheriting from that type (so called is-a relation). 7.4 Multiple dispatch The Seed7 object system allows multiple dispatch (not to be confused with multiple inheritance). The methods are not assigned to one type (class). The decision which function (method) is called at runtime is done based upon the types of several arguments. The classic object orientation is a special case where a method is connected to one class and the dispatch decision is done based on the type of the 'self' or 'this' parameter. The classic object orientation is a single dispatch system. In the following example the type 'Number' is introduced which is capable to unify numerical types. The type 'Number' is an interface type which defines the inferface function for the '+' operation: const type: Number is sub object interface; const func Number: (in Number param) + (in Number param) is DYNAMIC; The interface type 'Number' can represent an 'Integer' or a 'Float': const type: Integer is new struct var integer: val is 0; end struct; type_implements_interface(Integer, Number); const type: Float is new struct var float: val is 0.0; end struct; type_implements_interface(Float, Number); The declarations of the converting '+' operators are: const func Float: (in Integer: a) + (in Float: b) is func result var Float: result is Float.value; begin result.val := flt(a.val) + b.val; end func; const func Float: (in Float: a) + (in Integer: b) is func result var Float: result is Float.value; begin result.val := a.val + flt(b.val); end func; The declarations of the normal '+' operators (which do not convert) are: const func Integer: (in Integer: a) + (in Integer: b) is func result var Integer: result is Integer.value; begin result.val := a.val + b.val; end func; const func Float: (in Float: a) + (in Float: b) is func result var Float: result is Float.value; begin result.val := a.val + b.val; end func; The type 'Number' can be extended to support other operators and there can be also implementations using 'complex', 'bigInteger', 'bigRational', etc. . That way 'Number' can be used as universal type for math calculation. Further extending can lead to an universal type. Such an universal type is loved by proponents of dynamic typed languages, but there are also good reasons to have destinct types for different purposes. ================================ Thanks in advance for your effort. Greetings Thomas Mertes Seed7 Homepage: http://seed7.sourceforge.net Seed7 - The extensible programming language: User defined statements and operators, abstract data types, templates without special syntax, OO with interfaces and multiple dispatch. -- GMX FreeMail: 1 GB Postfach, 5 E-Mail-Adressen, 10 Free SMS. Alle Infos und kostenlose Anmeldung: http://www.gmx.net/de/go/freemail |
From: Leonardo C. <leo...@gm...> - 2008-02-12 11:02:47
|
2008/2/11, Thomas Mertes <tho...@gm...>: > The variable 'myAstro' is not a reference to a value, but the > value itself. The process described above makes sense for parameters > (except for a value parameter where the value is copied). > For structs the parameters 'in', 'ref' and 'inout' are reference > parameters. You have been really clear. In the manual chapter about parameters (chapter 6) I haven't found anything about structures but only about arrays. "For arrays 'in' parameters are equal to 'ref' parameters" Probably the structs behaviour may be inferred from what you said about arrays and from the sources but I think that specifying it would be better. > Something is clear now: My description of the process > of dynamic dispatch is not precise enough and needs improvement. I think the description is good: I simply wasn't aware that implementation objects have value-copy semantics. > May be my idea of having value copy for implementation objects > and reference copy for interface objects is too confusing. > May be I should describe the role of assignments in more detail. > What do you think about my concepts and their description? I think the idea it's not confusing but can be better documented. Thanks, Leonardo |
From: Leonardo C. <leo...@gm...> - 2008-02-12 07:52:53
|
2008/2/11, Thomas Mertes <tho...@gm...>: > "Leonardo Cecchi" <leo...@gm...> wrote (off-list): > > It works well also for me. > > I don't understand how this explicit "new" function will work: it will > > be used to initialize the interface variable like this? > > > > const proc: main is func > > local > > var strangeInterface: enterprise is new(astronave); > > begin > > (* something here *) > > end func; > > > > I think it's really useful to visually see when an interface variable > > points to a new value or to an existing implementation value. > > > > Thanks, > > > > Leonardo > Yes, it would be used exactly as in your example (maybe without > parentheses). In the moment I use special primitive actions to > create and assign interface variables with an implementation value. > This actions are 'CLS_CREATE2' and 'CLS_CPY2'. This actions accept > interface objects (category CLASSOBJECT) or implementation objects > (everything else, but intended to be of category STRUCTOBJECT). > If the refered implementation object is a temporary expression > it should be made permanent (which I forgot to do in the case > of CLS_CREATE2 - see below for the fix of the bug). > > The situation, that implementation objects can point to global or > local objects, which may be constant or variable, and also to > temporary objects (which should be made permanent in the assignment > or create action), is confusing. > > As you might guess there is a memory leak in this area. > I plan to use reference counting (or explicit frees when reference > counting is not enough). In that case I have to destinguish between > global and local objects (which need no reference counting) and > managed values (with reference counting). > > By the way, here is the fix for the bug you found > (the next version of Seed7 will contain it): > --- /home/tm/old_seed7_5/src/clslib.c 2008-02-10 15:47:51.000000000 +0100 > +++ /home/tm/new_seed7_5/src/clslib.c 2008-02-11 13:26:48.000000000 +0100 > @@ -175,6 +175,7 @@ > modu_to->value.objvalue = take_reference(modu_from); > } else { > modu_to->value.objvalue = modu_from; > + CLEAR_TEMP_FLAG(modu_from); > } /* if */ > return(SYS_EMPTY_OBJECT); > } /* cls_create2 */ > > BTW.: If possible I would prefer the discussion to be on > see...@li... > That way others can also follow the discussion. > > Greetings Thomas Mertes > > Seed7 Homepage: http://seed7.sourceforge.net > Seed7 - The extensible programming language: User defined statements > and operators, abstract data types, templates without special > syntax, OO with interfaces and multiple dispatch. > > -- > GMX FreeMail: 1 GB Postfach, 5 E-Mail-Adressen, 10 Free SMS. > Alle Infos und kostenlose Anmeldung: http://www.gmx.net/de/go/freemail > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio 2008. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > _______________________________________________ > Seed7-users mailing list > See...@li... > https://lists.sourceforge.net/lists/listinfo/seed7-users > I've tested the fix and it works well for me. Sorry, previously I've forgotten to forward the response to the mailing list. Thanks for the ready fix! Leonardo |
From: Thomas M. <tho...@gm...> - 2008-02-11 21:49:24
|
"Leonardo Cecchi" <leo...@gm...> wrote (off-list): > I've another question about dynamic dispatching. > In the new chapter you say: > > "Although there is a 'draw' function declared for 'circle' it is not > called directly. Instead the 'draw' interface function for 'shape' is > called. When the program is analyzed (in the interpreter or compiler) > *interface functions take precedence over normal functions* when both > are to be considered." > > I've made a little test: > > $ include "seed7_05.s7i"; > > const type: strangeInterface is new interface; > const func string: getNome(in strangeInterface param) is DYNAMIC; > > const type: astronave is new struct > var string: nome is ""; > end struct; > type_implements_interface(astronave, strangeInterface); > > const type: astronaveBetter is sub astronave struct > var integer: power is 0; > end struct; > type_implements_interface(astronaveBetter, strangeInterface); > > const func astronave: astronave(in string: nome) is func > result > var astronave: result is astronave.value; > begin > result.nome := nome; > end func; > > const func string: getNome(in astronave: a1) is func > result > var string: result is ""; > begin > result:=a1.nome; > end func; > > const func astronaveBetter: astronaveBetter(in string: nome, in > integer:power) is func > result > var astronaveBetter: result is astronaveBetter.value; > begin > result.nome := nome; > result.power := power; > end func; > > const func string: getNome(in astronaveBetter: a1) is func > result > var string: result is ""; > begin > result:=a1.nome & " better"; > end func; > > const proc: main is func > local > var astronaveBetter: myBetter is astronaveBetter("Enterprise > galactica ", 1500); > var strangeInterface: enterprise is astronave.value; > var astronave: myAstro is astronave.value; > begin > enterprise:=myBetter; > myAstro:=myBetter; > > writeln(getNome(enterprise)); > writeln(getNome(myAstro)); > end func; > > The output of this program is the following: > > C:\msys\1.0\home\lcecchi\seed7\src>hi provatre.sd7 > HI INTERPRETER Version 4.5.3082 Copyright (c) 1990-2008 Thomas Mertes > 259 C:/msys/1.0/home/lcecchi/seed7/lib/syntax.s7i > 3395 C:/msys/1.0/home/lcecchi/seed7/lib/seed7_05.s7i > 55 provatre.sd7 > 3709 lines total > 119645 lines per second > 1673829 bytes > Enterprise galactica better > Enterprise galactica > > I don't understand why it doesn't do a dynamic dispatching on the > second instruction. > The functions to be considered are: > > const func string: getNome(in strangeInterface param) is DYNAMIC; > const func string: getNome(in astronave: a1); > const func string: getNome(in astronaveBetter: a1); > > So the interface should have precedence on the other functions > considering that either "astronave" or "astronaveBetter" implements > the interface "strangeInterface". > I haven't understood something... Where I'm wrong? > Thanks, > > Leonardo The local variable 'myAstro' has the type 'astronave' which is a structure. Assignments of structures do a (deep) copy. The struct 'astronaveBetter' has more elements than 'astronave', but only the elements present in both structures are copied. The assignment 'myAstro:=myBetter' does a copy of the structure (The element 'nome' is copied). With that copy the information that 'myBetter' had the type 'astronaveBetter' is lost. My description of the process: "Although there is a 'draw' function declared for 'circle' it is not called directly. Instead the 'draw' interface function for 'shape' is called. When the program is analyzed (in the interpreter or compiler) *interface functions take precedence over normal functions* when both are to be considered." is right, but does not have the desired effect here. The variable 'myAstro' is not a reference to a value, but the value itself. The process described above makes sense for parameters (except for a value parameter where the value is copied). For structs the parameters 'in', 'ref' and 'inout' are reference parameters. In this cases a parameter of type 'astronave' can point to a value of type 'astronaveBetter'. In this cases a parameter of type 'astronave' behaves iside a function (method) like a parameter of type 'strangeInterface'. If you add to your example: const func integer: getPower (in strangeInterface param) is DYNAMIC; const func integer: getPower (in astronave: a1) is return 0; const func integer: getPower (in astronaveBetter: a2) is return a2.power; const func string: getPowerName (in astronave: a1) is return getNome(a1) & "-" & str(getPower(a1)); and add to the main program: writeln(getPowerName(myBetter)); you will get: Enterprise galactica better-1500 which is exactly what you expect. Something is clear now: My description of the process of dynamic dispatch is not precise enough and needs improvement. May be my idea of having value copy for implementation objects and reference copy for interface objects is too confusing. May be I should describe the role of assignments in more detail. What do you think about my concepts and their description? BTW.: If possible I would prefer the discussion to be on see...@li... That way others can also follow the discussion. Greetings Thomas Mertes Seed7 Homepage: http://seed7.sourceforge.net Seed7 - The extensible programming language: User defined statements and operators, abstract data types, templates without special syntax, OO with interfaces and multiple dispatch. -- Psssst! Schon vom neuen GMX MultiMessenger gehört? Der kann`s mit allen: http://www.gmx.net/de/go/multimessenger |
From: Thomas M. <tho...@gm...> - 2008-02-11 16:53:48
|
"Leonardo Cecchi" <leo...@gm...> wrote (off-list): > It works well also for me. > I don't understand how this explicit "new" function will work: it will > be used to initialize the interface variable like this? > > const proc: main is func > local > var strangeInterface: enterprise is new(astronave); > begin > (* something here *) > end func; > > I think it's really useful to visually see when an interface variable > points to a new value or to an existing implementation value. > > Thanks, > > Leonardo Yes, it would be used exactly as in your example (maybe without parentheses). In the moment I use special primitive actions to create and assign interface variables with an implementation value. This actions are 'CLS_CREATE2' and 'CLS_CPY2'. This actions accept interface objects (category CLASSOBJECT) or implementation objects (everything else, but intended to be of category STRUCTOBJECT). If the refered implementation object is a temporary expression it should be made permanent (which I forgot to do in the case of CLS_CREATE2 - see below for the fix of the bug). The situation, that implementation objects can point to global or local objects, which may be constant or variable, and also to temporary objects (which should be made permanent in the assignment or create action), is confusing. As you might guess there is a memory leak in this area. I plan to use reference counting (or explicit frees when reference counting is not enough). In that case I have to destinguish between global and local objects (which need no reference counting) and managed values (with reference counting). By the way, here is the fix for the bug you found (the next version of Seed7 will contain it): --- /home/tm/old_seed7_5/src/clslib.c 2008-02-10 15:47:51.000000000 +0100 +++ /home/tm/new_seed7_5/src/clslib.c 2008-02-11 13:26:48.000000000 +0100 @@ -175,6 +175,7 @@ modu_to->value.objvalue = take_reference(modu_from); } else { modu_to->value.objvalue = modu_from; + CLEAR_TEMP_FLAG(modu_from); } /* if */ return(SYS_EMPTY_OBJECT); } /* cls_create2 */ BTW.: If possible I would prefer the discussion to be on see...@li... That way others can also follow the discussion. Greetings Thomas Mertes Seed7 Homepage: http://seed7.sourceforge.net Seed7 - The extensible programming language: User defined statements and operators, abstract data types, templates without special syntax, OO with interfaces and multiple dispatch. -- GMX FreeMail: 1 GB Postfach, 5 E-Mail-Adressen, 10 Free SMS. Alle Infos und kostenlose Anmeldung: http://www.gmx.net/de/go/freemail |
From: Thomas M. <tho...@gm...> - 2008-02-11 10:59:47
|
"Leonardo Cecchi" <leo...@gm...> wrote: > I was reading the new manual chapter (it's the chapter I was looking > for) I discovered a strange issue. > I don't know if it's a bug but I can't explain to myself the behaviour > of the following program: > > $ include "seed7_05.s7i"; > > const type: strangeInterface is new interface; > const func string: getNome(in strangeInterface param) is DYNAMIC; > > const type: astronave is new struct > var string: nome is ""; > end struct; > type_implements_interface(astronave, strangeInterface); > > const func astronave: astronave(in string: nome) is func > result > var astronave: result is astronave.value; > begin > result.nome := nome; > end func; > > const func string: getNome(in astronave: a1) is func > result > var string: result is ""; > begin > result:=a1.nome; > end func; > > const proc: main is func > local > var strangeInterface: enterprise is astronave("Enterprise galactica"); > begin > writeln("one"); > writeln("the name:" & getNome(enterprise)); > writeln("two"); > end func; As far as I can see you discovered a bug. It has to do with the initialisation of interface variables. When you change the 'main' program to const proc: main is func local var strangeInterface: enterprise is astronave("Enterprise galactica"); begin enterprise := astronave("Enterprise galactica"); writeln("one"); writeln("the name:" & getNome(enterprise)); writeln("two"); end func; it works (at least for me). Does it work for you? I have not investigated more about the bug than that. It is obvious that I need to revise the initialisation of interface variables. In the meantime it is necessary to assign a value with := to an interface variable. There is more to revise in this area: It can happen that several interface variables point to one implementation value. Since this is sometimes desired and sometimes not I may move to the use of an explicit 'new' function. What do you think? Greetings Thomas Mertes Seed7 Homepage: http://seed7.sourceforge.net Seed7 - The extensible programming language: User defined statements and operators, abstract data types, templates without special syntax, OO with interfaces and multiple dispatch. -- Der GMX SmartSurfer hilft bis zu 70% Ihrer Onlinekosten zu sparen! Ideal für Modem und ISDN: http://www.gmx.net/de/go/smartsurfer |
From: Leonardo C. <leo...@gm...> - 2008-02-11 08:41:27
|
Hi. I was reading the new manual chapter (it's the chapter I was looking for) I discovered a strange issue. I don't know if it's a bug but I can't explain to myself the behaviour of the following program: $ include "seed7_05.s7i"; const type: strangeInterface is new interface; const func string: getNome(in strangeInterface param) is DYNAMIC; const type: astronave is new struct var string: nome is ""; end struct; type_implements_interface(astronave, strangeInterface); const func astronave: astronave(in string: nome) is func result var astronave: result is astronave.value; begin result.nome := nome; end func; const func string: getNome(in astronave: a1) is func result var string: result is ""; begin result:=a1.nome; end func; const proc: main is func local var strangeInterface: enterprise is astronave("Enterprise galactica"); begin writeln("one"); writeln("the name:" & getNome(enterprise)); writeln("two"); end func; The result is: C:\msys\1.0\home\lcecchi\seed7\src>hi provadue.sd7 HI INTERPRETER Version 4.5.3082 Copyright (c) 1990-2008 Thomas Mertes 259 C:/msys/1.0/home/lcecchi/seed7/lib/syntax.s7i 3395 C:/msys/1.0/home/lcecchi/seed7/lib/seed7_05.s7i 31 provadue.sd7 3685 lines total 118870 lines per second 1628430 bytes one So the execution is blocked at the line with "the name" and the line who writes "two" it's never executed. Where I'm wrong? Thanks, Leonardo |
From: Thomas M. <tho...@gm...> - 2008-02-10 15:03:56
|
Hello, I am writing a chapter about object orientation. It would be nice to get some feedback about it before the final release. Here is it: 7. OBJECT ORIENTATION ===================== The object orientation of Seed7 is based on terms like interface and implementation. An interface defines which methods are supported while the implementation describes how this is done. Several classes with different method implementations share the same interface. This view is not something new. When you write to a file (in C under UNIX) you use the same interface (higher level printf or lower level write) for harddisk files, console output and printer output. The implementation does totally different things for this files. UNIX uses the "everything is a file" philosopy for ages (even network communication uses the file interface (see sockets)). 7.1 Interface and implementation Seed7 uses interface types and implementation types. Objects declared with an interface type refer to a value which has an implementation type. The interface type of an object can always be determined at compile-time. Several implementation types can belong to one interface type (they implement the interface type). E.g.: The types 'NULL_FILE', 'external_file' and 'socket' implement the 'file' interface. An interface object can only refer to a value with an implementation type that implements the interface. E.g.: A 'shape' variable cannot refer to a 'socket'. A new interface type is declared with: const type: shape is new interface; Interface (DYNAMIC) functions describe what can be done with objects of an interface type. An interface function for a 'shape' could be: const proc: draw (in shape param, inout window param) is DYNAMIC; Now we know that it is possible to 'draw' a 'shape' to a 'window'. How this drawing is done is described in the implementation type. An implementation type for 'shape' is: const type: circle is new struct var integer: radius is 0; end struct; The fact that the type 'circle' is an implementation type of 'shape' is described with: type_implements_interface(circle, shape); The function which implements 'draw' for 'circle's is: const proc: draw (in circle: aCircle, inout window: aWindow) is func begin circle(aWindow.win, aWindow.currX, aWindow.currY, aCircle.radius, aWindow.foreground); end func; In the classic OOP philosopy a message is sent to an object. In the method the receiving object is referred with 'self' or 'this'. The other parameters use the same mechanisms as in procedural programming languages (value or reference parameter). Seed7 uses a different approach: All parameters get a user defined name. In the above example the name 'aCircle' was used for the 'self'/'this' parameter. A function to create new circle objects can also be helpful: const func circle: circle (in integer: radius) is func result var circle: result is circle.value; begin result.radius := radius; end func; Now we can draw a 'circle' object with: draw(circle(50), aWindow); Although there is a 'draw' function declared for 'circle' it is not called directly. Instead the 'draw' interface function for 'shape' is called. When the program is analyzed (in the interpreter or compiler) interface functions take precedence over normal functions when both are to be considered. The interface function for 'shape' decides which implementation function has to be called. This decision process is called dynamic dispatch. In the above example the overhead of the dynamic dispatch seems to be unnecessary, but in general it is the way object orientation works also in other languages. 7.2 Dynamic dispatch When the implementation types have different implementations of the same function (method) a dynamic dispatch is necessary. The type of the value, refered by an interface object, is not known at compile-time. In this case the program must decide at runtime which implementation of the function should be invoked. This decision is based on the type of the value of an object. A dynamic dispatch is described with a dynamic (or interface) function. To demonstrate the dynamic dispatch we define the type 'line' which also implements a 'shape': const type: line is new struct var integer: xLen is 0.0; var integer: yLen is 0.0; end func; type_implements_interface(line, shape); const proc: draw (in line: aLine, in window: aWindow) is func begin line(aWindow.win, aWindow.currX, aWindow.currY, aLine.xLen, aLine.yLen, aWindow.foreground); end func; const func line: line (in integer: xLen, in integer: yLen) is func result var line: result is line.value; begin result.xLen := xLen; result.yLen := yLen; end func; In addition we define a normal (not DYNAMIC) function which draws 'shape's to the 'currWindow': const proc: draw (in shape: aShape) is func begin draw(aShape, currWindow); end func; In the above example the call of the (DYNAMIC) interface function is 'draw(aShape, currWindow)'. For this call the dynamic dispatch works as follows: - For all parameters which have an interface type the parameter is replaced with its value. In this case the parameter 'aShape' is replaced by a value of type 'circle' or 'line'. - The same logic as in the analyze part of the compiler is used to find the matching function. This time normal functions take precedence over interface functions. - When a matching function is found it is called. This process describes the principal logic of the dynamic dispatch. In practice it is not necessary to execute the analyze part of the compiler during the runtime. It is possible to simplify this process with tables and function pointers. 7.3 Inheritance When a new 'struct' type is defined it is possible to inherit from an existing 'struct' type. E.g.: const type: external_file is sub NULL_FILE struct var PRIMITIVE_FILE: ext_file is PRIMITIVE_NULL_FILE; var string: name is ""; end struct; That way the type 'external_file' inherits the fields and methods of 'NULL_FILE'. In most situations it makes sense when the implementation types inherit from a basic implementation type such as 'NULL_FILE'. In other OO languages the distinction between interface type and basic implementation type is not done. Such languages either use a dynamic dispatch for every method call (as Java does) or need a keyword to request a dynamic dispatch (as C++ does with the 'virtual' keyword). A new interface type can also inherit from an existing interface type: const type: shape is sub object interface; Although inheritance is a very powerful feature it should be used with care. In many situations it makes more sense that a new type has an element of another type (so called has-a relation) instead of inheriting from that type (so called is-a relation). 7.4 Multiple dispatch The Seed7 object system allows multiple dispatch (not to be confused with multiple inheritance). The methods are not assigned to one type (class). The decision which function (method) is called at runtime is done based upon the types of several arguments. The classic object orientation is a special case where a method is connected to one class and the dispatch decision is done based on the type of the 'self' or 'this' parameter. The classic object orientation is a single dispatch system. In the following example the type 'Number' is introduced which is capable to unify numerical types. The type 'Number' is an interface type which defines the inferface function for the '+' operation: const type: Number is sub object interface; const func Number: (in Number param) + (in Number param) is DYNAMIC; The interface type 'Number' can represent an 'Integer' or a 'Float': const type: Integer is new struct var integer: val is 0; end struct; type_implements_interface(Integer, Number); const type: Float is new struct var float: val is 0.0; end struct; type_implements_interface(Float, Number); The declarations of the converting '+' operators are: const func Float: (in Integer: a) + (in Float: b) is func result var Float: result is Float.value; begin result.val := flt(a.val) + b.val; end func; const func Float: (in Float: a) + (in Integer: b) is func result var Float: result is Float.value; begin result.val := a.val + flt(b.val); end func; The declarations of the normal '+' operators (which do not convert) are: const func Integer: (in Integer: a) + (in Integer: b) is func result var Integer: result is Integer.value; begin result.val := a.val + b.val; end func; const func Float: (in Float: a) + (in Float: b) is func result var Float: result is Float.value; begin result.val := a.val + b.val; end func; The type 'Number' can be extended to support other operators and there can be also implementations using 'complex', 'bigInteger', 'bigRational', etc. . That way 'Number' can be used as universal type for math calculation. Further extending can lead to an universal type. Such an universal type is loved by proponents of dynamic typed languages, but there are also good reasons to have destinct types for different purposes. ================================ Thanks in advance for your effort. Greetings Thomas Mertes Seed7 Homepage: http://seed7.sourceforge.net Seed7 - The extensible programming language: User defined statements and operators, abstract data types, templates without special syntax, OO with interfaces and multiple dispatch. -- Psssst! Schon vom neuen GMX MultiMessenger gehört? Der kann`s mit allen: http://www.gmx.net/de/go/multimessenger |
From: Thomas M. <tho...@gm...> - 2007-09-09 19:55:32
|
Welcome to the Seed7 discussion list This list is for Seed7 user and developer discussions. Feel free to ask any questions about Seed7. Greetings Thomas Mertes Seed7 Homepage: http://seed7.sourceforge.net Seed7 - The extensible programming language: User defined statements and operators, abstract data types, templates without special syntax, OO with interfaces and multiple dispatch. -- Psssst! Schon vom neuen GMX MultiMessenger gehört? Der kanns mit allen: http://www.gmx.net/de/go/multimessenger |