Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changes between Version 25 and Version 26 of Sysel


Ignore:
Timestamp:
2010-05-20T19:56:21Z (11 years ago)
Author:
Jiri Svoboda
Comment:

Remove ideas

Legend:

Unmodified
Added
Removed
Modified
  • Sysel

    v25 v26  
    55 * [https://launchpad.net/sysel Sysel project at launchpad]
    66 * [http://trac.helenos.org/trac.fcgi/browser/head/uspace/dist/src/sysel/demos Examples of real (working) Sysel code]
     7 * [wiki:Sysel/Ideas Description of planned features and ideas]
    78
    89Note that Sysel syntax is not finalized. Some important language features are missing at the moment (especially visibility control and packaging) so the examples presented will need to change when these are implemented.
     
    4647 * method and operator overloading
    4748 * code organization (packages and modules)
    48 
    49 == Ideas for Sysel ==
    50 
    51 Notes on features which are almost certain to appear in Sysel in one way another.
    52 
    53 === Code organization ===
    54 
    55 Sysel shall employ ''packages'' and ''modules''. Together, these two constructs provide full information about organization of the codebase and allow for a certain degree of freedom in how finely the code is partitioned, both in terms of namespace and code volume.
    56 
    57 ==== Packages ====
    58 
    59 Packages provide two main features: a namespace and visibility controls. Packages thus provide a greater level of isolation than mere classes and allow safe composition of code developed by different (uncoordinated) teams. Packages can have a well defined API/ABI and can be delivered in compiled form via libraries. Each package has a name which must be fully qualified.
    60 
    61 Within a package all symbol references only need to be qualified relative to the package. To reference symbols outside of the current package they must be either imported or the reference must be fully qualified. (TODO: Should we enforce explicit import of all symbols?) Symbols can only be imported individually or in a qualified manner. This ensures that there can be no collisions of symbols from different namespaces (which need not be under the control of the same entity). When importing symbols the symbols being imported must be specified using their fully qualified names.
    62 
    63 ==== Modules ====
    64 
    65 Modules provide a complementary and finer-grained means of decomposition. Usually each source file corresponds to exactly one module. For each module we define its (unqualified) name and fully qualified name of the package it belongs to (which 'anchors' it in the code base). Conversely, each package specifies all modules it consists of. Consequently, for each module we can determine which package it belongs to and for each package we can determine all modules (and thus all symbols) it consists of.
    66 
    67 As we explained, modules allow the source code to be broken into separate files and at the same time tie it together in a formal manner. When building a package or program, there is thus no need to specify all its source files informally in a makefile. It is sufficient to point the compiler to directories where it should look for source files and tell it which package we want built.
    68 
    69 Modules do not represent a namespace. Any symbols defined or imported in one module will be accessible (unqualified) in any other module within the same package. Names of global symbols in all modules of a package must therefore be coordinated. Note that due to object-oriented nature of the language there are usually not very many global symbols defined in a package and also packages are assumed to be under the control of a single entity.
    70 
    71 Definitions of classes can be split across multiple modules (but not packages). Thus large classes can be split accross multiple source files.
    72 
    73 === Dynamic linking ===
    74 
    75 It should be possible to use, with similar simplicity and the same level of static type checking, not only ''compulsory libraries'', but also ''optional libraries'' and ''plugin libraries''.
    76 
    77 Compulsory libraries are those required every time the executable is invoked (equivalent to `gcc -lname`). Optional libraries are only loaded once the application touches some symbol from the library. This is a very useful feature that allows building binaries with all optional dependencies enabled, yet the user need not install all these libraries if they do not want to. This helps avoiding ''dependency avalanches''.
    78 
    79 Plugin libraries are those where multiple libraries can exist written again some common plugin interface. One possibility is to have ''packages'' implement ''package interfaces''. A package could be loaded at run time, a reference to it stored to a variable whose type is the ''package interface'' type. Then it would be possible to refer to symbols within the dynamic package using standard qualified names (e.g. `P.symbol`). This enables full static type checking / interface checking for both the implementor and user of the plugin.
    80 
    81 === Remote objects ===
    82 
    83 ==== Basics ====
    84 
    85 HelenOS IPC is usually employed in an RPC-like style. Remote objects would support asynchronous messaging in the language itself. Remote object classes (and interfaces) form a separate hierarchy of inheritance to the ''local'' classes and interfaces. Remote interfaces are equivalent to IPC interfaces now usually defined in HelenOS in `uspace/lib/c/include/ipc`. They would naturally support (multiple) inheritance. Servers contain remote classes which implement these interfaces.
    86 
    87 When a client wants to use some service, they are given a reference to a remote object. This reference identifies not only the server which we talk to, but possibly also the individual resource within the server that we are accessing. For a contrived example, a console server might provide the two interfaces:
    88 
    89 {{{
    90 interface IConsole, remote is
    91         fun GetVC(vc_index : int) : IVC;
    92 end
    93 
    94 interface IVC, remote is
    95         fun GotoXY(x, y : int);
    96         fun Write(s : string);
    97 end
    98 }}}
    99 
    100 When we invoke the GetVC() method, the console server will pass us a reference to the remote object implementing the requested VC. Then we can work with this particular VC using that reference:
    101 
    102 {{{
    103 var Con : IConsole;
    104 var VC : IVC;
    105 
    106 C = NameService.GetConnection("console") as IConsole;
    107 VC = C.GetVC(2);
    108 VC.GotoXY(10, 10);
    109 VC.Write("Hello World!");
    110 }}}
    111 
    112 Connection creation and termination, as well as transaction management (identifying the objects being worked with) is automatically handled by the language run-time. Also handled automatically is the creation of threads and fibrils within a server. A server can potentially handle any number of parallel requests (though it might be possible to limit this with some quota, if required). Concurrent access to remote objects is possible (and often desired).
    113 
    114 ==== Remote invocation ====
    115 
    116 When a method of a remote object is invoked, the method ID and its parameters are serialized and the resulting message is sent to the server. On the server the method ID and arguments are de-serialized and the implementation of the method is invoked. When the method returns, the return value (and possibly output arguments) are serialized and sent back to the client. At the client the return value(s) are de-serialized and returned to the caller.
    117 
    118 Some notes:
    119  * Multiple threads/fibrils may use the same remote object in parallel without fear of blocking each other (as long as the server is properly implemented)
    120  * Stateful services can be implemented by the server handing out state objects (such as open-file object on a file server).
    121 
    122 ==== Promises ====
    123 
    124 [http://en.wikipedia.org/wiki/Futures_and_promises Promises] can be used to express asynchronous behavior and potentially allow for [http://en.wikipedia.org/wiki/Promise_pipelining#Promise_pipelining promise pipelining] (a form of optimization). In our case it would suffice to have a specialized form of promise, one that promises some data to be delivered from a remote object. Promises would be declared using a prefix type operator `future`.
    125 
    126 As long as the data received from a remote object stays in a type that is `future`, it is handled in an asynchronous fashion. Once the data is converted to a non-future type, the execution blocks until the data is received.
    127 
    128 Example:
    129 
    130 {{{
    131 interface IAsyncIO is
    132         fun AReadBlock(addr : int) : future Block;
    133 end
    134 }}}
    135 
    136 {{{
    137 fun ReadBlocksParallel(start_addr, count : int) : Block[] is
    138         var fblock : (future Block)[];
    139 
    140         for i in range(0, count) do
    141                 -- This does not block
    142                 fblock[i] = AReadBlock(start_addr + i);
    143         end
    144 
    145         -- All reads are now being executed in parallel.
    146 
    147         -- Each array element is implicitly converted from future Block to Block.
    148         -- This blocks until all data has been received.
    149         return fblock;
    150 end
    151 }}}
    152 
    153 === String language specification ===
    154 
    155 It has been suggested by Pavel Rimsky that very often string literals in a program contain data in some machine readable language (e.g. format strings, SQL statements) or references to external resources. It might be useful to be able to somehow specify this in the program, so that external tools could recognize and work with these for purposes such as syntax checking, refactoring, etc.
    156 
    157 Note: That means ''identifying'' the language the string contains. Defining any ''properties'' (e.g. syntax) of the language the string contains is out of scope!
    158 
    159 One typical example here is a formatting function. The format string argument is in a well-defined language. Here it would be useful to specify language of the formal argument. With any use of such function the compilation tools could try to verify the real argument. Similarly we might to specify language for a member variable.
    160 
    161 A different approach is specifying language of a string literal in situ. This is reminiscent of (X)HTML which allows embedding pieces of code written in different languages (e.g. CSS, ECMAscript) while specifying the external language using its MIME type, or language constructs such as "extern C".
    162 
    163 Both approaches could be combined.
    164 
    165 TODO: Consider where language annotations would be useful and how they should be realized lexically and syntactically. (Must look pretty!)
    166 
    167 === Miscellaneous ideas ===
    168 
    169 These ideas are considered for inclusion (but need not be included). They need elaborating.
    170 
    171 ==== Member pointers ====
    172 
    173 Delegates identify the object instance and method to be called (but not the arguments). Conversely, member pointers identify the method to be called, but not the arguments and not the object instance (It can be invoked on any object which is instace of a given class). This feature comes from C++.
    174 
    175 ==== True inner classes ====
    176 
    177 A true inner class is non-static in the sense that any instance of this class implicitly contains a reference to some instance of the outer class. Thus the inner class is constructed in non-static context (in context of an object instance) and the outer object can be referenced via a keyword.
    178 
    179 ==== Output function arguments ====
    180 
    181 Semantically equivalent to additional return values of a function. A simple way to return multiple values (especially since Sysel does not have tuples).
    182 
    183 ==== Built-in associative arrays ====
    184 
    185 Maps and sets are so commonly used and so immensely useful that it might be worth incorporating into the langauge core. This could bring greater ease of use and optimization opportunities.