The ObjectSense Programming Language : An object-oriented reincarnation of VimL
| script karma
Downloaded by 225
Comments, bugs, improvements
script versions (upload new version)
|ObjectSense is a superset of VimL8, and has all the main features of a modern object-oriented language, such as data encapsulation, polymorphism, inheritance, etc. On top of the language implementation, rose - a module manager is provided, which is also built into the language runtime. It's very developer friendly, especially for those who already have a working knowledge of VimL8 can effortlessly expand their skills to code in ObjectSense.
As a bonus feature, polyglot programming is easily doable in ObjectSense. Currently vim8 and vim9 are supported, with minimal work the list can grow longer to include other languages, such as, python, ruby, lua, etc. However, as far as the operating system is concerned, only Linux and MacOS are supported at the moment. There is a user-defined command, UT, for doing unit tests of the current class. It's very convenient for accessing class data in unit tests. No need for finding workaround to the language barrier when accessing such data in white box testing. Every component can be properly tested! Pure and simple! By following a few simple conventions and thanks to the built-in modular mechanism in the language runtime, ObjectSense programs are very scalable and development work can be distributed comfortably among team members.
In a more programming linguistic point of view, ObjectSense is of imperative paradigm on the surface, but carries functional programming abilities. In the language runtime, each object has its own data and functions, there's nothing shared. An object is entirely in its own universe just like functional programming. Because the lack of time, we haven't explored such property of the language much. Hopefully, the community can shed new lights on such nice combination.
This is a strong demonstration of what VimL8 is capable of. ObjectSense takes less than 5000 lines of code for the core of the language implementation. Although it's a superset of an existing language, it's very hard to imagine using such little code for implementing a non-trivial programming language. VimL8 has a lot of unrealised potentials, people really shouldn't jump off the bandwagon too quickly.
The best argument for vim9 is performance. We have found a way kind of 'compile' or speedup the load time for ObjectSense. In practice, we could really compile such code into binary and wire it with the language runtime, and without asking developers to learn a completely new language, i.e., being 100% compatible with existing VimL8 syntax and have the acclaimed performance at the same time. However, in our scenario ObjectSense performance issues have been tackled by the semi-compile approach, so no effort was directed to do the real compiling work which could bloat the code base exponentially.
Please download and untar the tarball, start from object/doc/readme.txt.
|1. move the downloaded tarball to ~/.vim directory, and untar it
mv onecloud-object-sense.tar.gz ~/.vim
tar -xvf onecloud-object-sense.tar.gz
2. open .vimrc and add a line
3. add the following in .vimrc for doing ObjectSense development
const g:OBJECT_SENSE_DEV = 1
4. to get a taste of the language, check out ~/.vim/object/demo subdirectories
Click on the package to download.
ip used for rating: 126.96.36.199
||This is a tremendous update, which really takes ObjectSense into another level and no other language has done before! It can be the ultimate form of literate programming or even beyond literate programming. We started out doing object-oriented programming in vimL, never thought would end up anything like this.
Now we can have functional, procedural, object-oriented, imperative, declarative, or any existing programming paradigms under one host language - vimL. Polyglot programming can be as easy as abc.
A new directive Let is added to the language. As a result, we no longer need to have CreateInstance calls when creating new objects. Thusly, making ObjectSense very clean from vimL, only ObjectSense directives and annotations are required when expressing the language. Also there are other new directives added to aid with day to day programming chores from this release.
1. A new programming construct called micro is introduced. This feature is
conceptually like lisp macro, which blends in the host language seamlessly
and extends linguistic functionality on source code level. Because the
name macro is already taken by vim to mean something else, in order to
avoid confusion and make the distinction of lisp macro, the word 'micro'
is chosen to depict a small piece of code that can have special
interpreting meaning other than the host language, which is vimL in here.
However, unlike other lisp-like macros, there's no AST involve in our
micro implementation, since vim doesn't use AST at runtime and its parser
is hand-crafted. As a result, ObjectSense requires developers to manually
define the parser, and have the result presented as a vim statement that
can be executed. Nevertheless, because there's no host language or AST
restriction, it can make the DSL much more expressive and have free style
syntax. It's a breeze to embed code from any programming language in
ObjectSense. VimL already has a tone of built-in functions to deal with
strings, it shouldn't be too much effort for a workable DSL parser.
Basically, what the parser does is to take an input of string and convert
it into a vim statement. The micro framework will execute the statement
once it's returned from the parser.
In lisp-like macros implementations, macros are often compiled, making
them as effective as the host language. However, the current
implementation of micro is not compiled, it has some performance cost.
Future work is planning to compile ObjectSense into vimL9 instructions
while retaining it as a superset of vimL8 syntactically. So vimL9 would
act some kind of VM just like the famous JVM, and ObjectSense will provide
compiler tools for micro/DSL implementations that need performance boost.
From a different perspective, micro puts a layer between the host language
and the guest language, whereas lisp-like macros are sharing the same
execution context directly with the host language. Micro provides better
protection to the host language runtime than traditional APIs and macros,
because the interface between them are strictly available only through the
guest language parser. Also, micros can have richer expressiveness and
abstraction than APIs and macros.
In real project practice and as time progresses, it's very easy for APIs
and macros to leak internal details to the client code. However,
abstraction through micro DSL would make it much harder to leak the
encapsulating data, because they don't share the same runtime.
Inherently, the side-effects for the usage of micros are much manageable
albeit not immutable.
Programmers can define their extensions to the language as they like by
using micro. The module dependency mechanism from rose also works with
micro. We can export APIs as well as micros in module description file
Sense.ose. However, the following example demonstrates only exporting
micros, no functions, from MyClass.
For the client code that uses micros from MyClass
Notice <bang> or '!' version of Import was adapted to work with importing
micros from a class.
To create a new micro called Python with the interpreter defined in
s:RunPython, we would have something like the following
Micro Python s:RunPython
function! s:RunPython(code, extra)
" just print out whatever was in code
To run Python micro, we could have,
Python hello world
Or define a function that would be interpreted by Python micro,
This is greeting from python.
call s:Greeting() "<--- print 'This is greeting from python'
Variable expansion and string interpolating are taken place before
invoking the interpreter for the micro.
2. Introduced Let directive, the first letter is upper case L, for assigning
and declaring new objects. We have Dart 2.0 like syntax for create new
objects with the Let directive. For example,
Let object = MyClass()
This directive let us drop the use of global function CreateInstance, so
being a superset of vimL, the semantics of the language can be defined by
the ObjectSense language directives and annotations only, no exposure to
any functions or other language constructs from vimL.
The Let directive also supports static constants. To define a static
constant we have the following syntax, in Preload
Let! GLOBAL_VAR = "this is a global variable"
To access in another class, we have to borrow it first,
echo s:GLOBAL_VAR " <--- prints "this is a global variable"
The Let directive also supports inline variable. The following is an
example use of such construct.
Let >> context = "http context"
To use the inline variable context in another class, we will have
Let << context
echo context " <--- prints "http context"
3. Switch statements are supported now, which can take different operators
which are compatible with vim operator, see :h expr4, there's one more
operator, instanceof, added to support type checking.
Switch object instanceof
Case v:t_string echo "this is a string"
Case MyClass echo "this my class"
Default echo "not recognised class from object: " . string(object)
4. Refine control over module dependency, making the mechanism more workable
with real-life projects. Before sourcing ObjectSense.vim, users can set
g:PRIVILEGED_MODULES variable to allow 3 or less modules that have the
privilege to add dependent modules at runtime.
5. For more examples, see demo/micro directory.
6. The next release will focus on supporting Nvim. Hopefully, ObjectSense
can bring vim and nvim plugin developers under the same roof again.
||1. Supported the granularity of export level down to each accessible function
of a class for a module without compromising performance. Three are three
levels of access rights are supported in module export, namely, they are
package, class, and function.
For the export function to work, we have to export its class first, and
then the function export of a class follows either explicit rule or
implicit rule. If there's no explicit rule specified for an export class,
then all the functions for that class will be implicitly exported.
Otherwise, only those explicitly specified functions will be exported.
There are three levels of access controls for a class. The first one is
module export which is available for all the modules. This is equivalent
of 'open' for Swift. The next one is internally available within a module
this is where 'accessible' is specified for a function, which is the
equivalent of 'internal' for Swift. The third one is private access
within a class, for functions that have no 'accessible' annotation
attached but have a 's:' in front of the function name.
2. Support adding pluggable commands to rose. First at all, developer use
the 'command' attribute to define the command name and command callback in
Sense.ose. For example:
command bundle mycompany.object.bundle.BundleCommand
defines a command called 'bundle', and have the BundleCommand in the
above package as the command callback which inherits a new export class
object.RoseCommand and implement the details in function s:Execute(...).
3. Introduced a new export class SenseParser which helps customised attributes
to be defined by developers to store module specific data or settings.
This works very much like command attribute. First at all, define the
attribute name and the parser to the attribute.
parser cockpit mycompany.object.cockpit.CockpitParser
define an attribute called 'cockpit', which will have its data parsed by
CockpitParser. It has three methods, namely, s:OnCommence, s:Process and
s:OnCompletion. The first method is called before the parsing. The
second one is called by the framework when parsing each line of attribute
data. The final one is invoked when finished parsing Sense.ose file.
4. Supported export class for inheritance.
5. Support loading multiple modules in QuickStart.
6. Added bash command line completion for rose.
7. Fixed some bugs in module accessibility.
8. Adding more test cases.
||1. 'rose test' is able to give a line-based test coverage report and
highlight the lines that are not covered by test
For example, run the test coverage on rose package that comes with ObjectSense,
rose test rose -c
Open the browser and visit the generated html.
2. supported polyglot in QuickStart
3. introduce UnitTestBelow directive which prevents loading unit test code in
4. refactor quite a few number of variable and function names
5. tighten up some loose logic and fixed a bunch of bugs
6. provide object.Runtime class to work with the modules at runtime