Difference between revisions of "SCL Tutorial"

From Developer Documents
Jump to navigation Jump to search
 
(3 intermediate revisions by the same user not shown)
Line 81: Line 81:
 
== Importing functionality from Java ==
 
== Importing functionality from Java ==
  
Java interfaces and classes can be imported to Java with annotated data definitions:
+
Java interfaces and classes can be imported from Java by declaring them inside importJava block:
 
<pre>
 
<pre>
@JavaType "java.util.regex.Pattern"
+
importJava "java.util.regex.Pattern" where
data Pattern
+
    data Pattern
  
@JavaType "java.util.List"
+
importJava "java.util.List" where
data List a
+
    data List a
 
</pre>
 
</pre>
  
There are SCL macros for calling constructors and methods of the classes and
+
Java methods, constructors and fields can be similarly imported by giving
accessing fields. These macros are defined in http://www.simantics.org/Java.
+
their type annotations in importJava block:
 
<pre>
 
<pre>
import "http://www.simantics.org/Java" as Java
+
importJava "java.util.regex.Pattern" where
 +
    @JavaName compile
 +
    compilePattern :: String -> Pattern
  
compilePattern : String -> Pattern
+
    @JavaName matcher
compilePattern = Java.staticMethod "java.util.regex.Pattern.compile"
+
    createMatcher :: Pattern -> String -> <Proc> Matcher
  
@JavaType "java.util.regex.Matcher"
+
importJava "java.util.regex.Matcher" where
data Pattern
+
    data Matcher
  
createMatcher: Pattern -> String -> Proc Matcher
+
    @JavaName matches
createMatcher = Java.methodProc "matcher"
+
    matcherMatches :: Matcher -> <Proc> Boolean
  
matcherMatches: Matcher -> Proc Boolean
+
matches : Pattern -> String -> <Proc> Boolean
matcherMatches = Java.methodProc "matches"
+
matches pattern text = do
 
+
    matcherMatches (createMatcher pattern text)
matches : Pattern -> String -> Boolean
 
matches pattern text = runProc (createMatcher pattern text >>= matcherMatches)  
 
 
</pre>
 
</pre>
  
 
Another example:
 
Another example:
 
<pre>
 
<pre>
createArrayList : Proc (List a)
+
importJava "java.util.ArrayList" where
createArrayList = Java.constructorProc "java.util.ArrayList"
+
    @JavaName "<init>"
 +
    createArrayList :: () -> <Proc> List a
  
createArrayListWithCapacity : Integer -> Proc (List a)
+
    @JavaName "<init>"
createArrayListWithCapacity = Java.constructorProc "java.util.ArrayList"
+
    createArrayListWithCapacity :: Integer -> <Proc> List a
  
sizeList : List a -> Proc Integer
+
    @JavaName size
sizeList = Java.methodProc "size"
+
    sizeList :: List a -> <Proc> Integer
  
getList : List a -> Integer -> Proc a
+
    @JavaName get
getList = Java.methodProc "get"
+
    getList :: List a -> Integer -> <Proc> a
  
setList : List a -> Integer -> a -> Proc ()
+
    @JavaName set
setList = Java.methodProc "set"
+
    setList :: List a -> Integer -> a -> <Proc> ()
  
addList : List a -> a -> Proc Boolean
+
    @JavaName add
addList = Java.methodProc "add"
+
    addList :: List a -> a -> <Proc> Boolean
 
</pre>
 
</pre>
  
Names of classes and methods must be compile time constants. Also the type of the method must be completely defined, because SCL compiler cannot infer the type from the Java method. Java method signature is however checked to be compatible with SCL type. Overloaded methods are handled by filtering out those methods whose signatures do not match.
+
Java constructor is referred with "<init>". If Java method name and SCL name matches the annotation @JavaName can be left out. Java import mechanism tries to be quite flexible. It provides some arguments based on the effects the function has. It also ignores the return value of the Java method if return type is () in SCL.  
 
 
The complete list of functions for accessing Java classes and interfaces is:
 
* constructor, constructorProc
 
* method, methodProc
 
* staticMethod, staticMethodProc
 
* field, fieldProc
 
* staticField, staticFieldProc
 
* setField
 
 
 
Macro ''constructor'' expects the full class name as a parameter. Macros ''staticMethod'' and ''staticField'' expect the full method or field name including the full name of the class containing the method or field. Macros ''method'', ''field'' and ''setField'' expect only the name of the method or field without the containing class name.
 
 
 
xxxProc-variants of the macros access Java methods that are not referentially transparent (have side-effects). They expect Proc Something as a return type of the function. Note that although functions ''staticField'' and ''field'' only read a value of the field, they are not referentially transparent if it is possible that the value of the field changes.
 
 
 
It is common that Java methods that have side-effects can be combined so that resulting methods are side-effect free. SCL function
 
<pre>runProc : Proc a -> a</pre>
 
can be used to declare that the procedure actually is referentially transparent. See above how it was used to defined matches function. It should be used sparingly in ordinary SCL code, because if it is used for a procedure that is not actually referentially transparent, strange behavior can occur when the compiler reorders or removes dead code.
 
  
A major functionality currently still missing is the ability to create new implementations of existing Java interfaces in SCL code or extend an existing class. This can be worked around currently by writing new implementations in Java and creating them with constructor macro.
+
A major functionality currently still missing is the ability to create new implementations of existing Java interfaces in SCL code or extend an existing class. This can be worked around currently by writing new implementations in Java.

Latest revision as of 15:21, 22 November 2016

Getting started

The easiest way of getting started with SCL is to use SCL console that is included in almost all Simantics-based products. You can open the console by pressing ALT-SHIFT-q and then q and choosing "SCL Console" from the list of views.

SCL console works by executing commands you write into the input box in the bottom of the view. After the command has been written, it can be executed by pressing ENTER. However, this works only if the command contains no syntactic errors. Possible errors are highlighted in the input box and a description of the error is shown when you move mouse on top of the highlighted text.

Multiline commands can be written by pressing CTRL-ENTER (or just ENTER when the current command text contains errors). The command history can be browsed with CTRL-UP and CTRL-DOWN.

If the command you write into console results as an ordinary value, it is just printed to the console. Here are couple of examples you can try:

> 13
13
> 1+2
3
> sin 1
0.8414709848078965
> "Hello " + "world!"
Hello world!
> [1,3,5]
[1, 3, 5]

You can also declare local variables to be used in the commands:

> x = 35
> y = 40
> x + y
75
> x * y
1400

Also new functions can be defined:

> f x = x * x
> f 123
15129

If you write a command that has side-effects, it is executed in the console:

> print "Hello" ; print "world!"
Hello
world!

SCL is a dialect of Haskell and tutorials written for Haskell can be used for learning the details of the language. The main differences between the languages are the strict evaluation strategy used in SCL and somewhat different standard library. Some Haskell tutorials can be found at http://www.haskell.org/haskellwiki/Learning_Haskell.

Extending SCL environment

The SCL values, data types etc. that are available in expressions and commands are defined in SCL modules. Currently all SCL modules must be part of the product plugins (in the future, you can also write modules inside the models). Each module is identified by a URI.

SCL module is a text file ending with extension ".scl". The recommended place for modules is scl/ folder under plugin root, but also other directories can be used:

scl/Test1.scl:

fib :: Integer -> Integer
fib x | x <= 1    = 1
      | otherwise = fib (x-1) + fib (x-2)


A directory is declared as a SCL package with the following kind of extension points defined in org.simantics.scl.runtime:

   <extension point="org.simantics.scl.runtime.package">
      <package URI="http://www.simantics.org/Tests"
               directory="scl"/>
   </extension> 

The module is not automatically available in the console, but you must run an import declaration:

> import "http://www.simantics.org/Tests/Test1" as Test1
> Test1.fib 13
377

Import declaration can also be used in modules to refer other modules. Cyclic module dependencies are not allowed.

Importing functionality from Java

Java interfaces and classes can be imported from Java by declaring them inside importJava block:

importJava "java.util.regex.Pattern" where
    data Pattern

importJava "java.util.List" where
    data List a

Java methods, constructors and fields can be similarly imported by giving their type annotations in importJava block:

importJava "java.util.regex.Pattern" where
    @JavaName compile
    compilePattern :: String -> Pattern

    @JavaName matcher
    createMatcher :: Pattern -> String -> <Proc> Matcher

importJava "java.util.regex.Matcher" where
    data Matcher

    @JavaName matches
    matcherMatches :: Matcher -> <Proc> Boolean

matches : Pattern -> String -> <Proc> Boolean
matches pattern text = do
    matcherMatches (createMatcher pattern text)

Another example:

importJava "java.util.ArrayList" where
    @JavaName "<init>"
    createArrayList :: () -> <Proc> List a

    @JavaName "<init>"
    createArrayListWithCapacity :: Integer -> <Proc> List a

    @JavaName size
    sizeList :: List a -> <Proc> Integer

    @JavaName get
    getList :: List a -> Integer -> <Proc> a

    @JavaName set
    setList :: List a -> Integer -> a -> <Proc> ()

    @JavaName add
    addList :: List a -> a -> <Proc> Boolean

Java constructor is referred with "<init>". If Java method name and SCL name matches the annotation @JavaName can be left out. Java import mechanism tries to be quite flexible. It provides some arguments based on the effects the function has. It also ignores the return value of the Java method if return type is () in SCL.

A major functionality currently still missing is the ability to create new implementations of existing Java interfaces in SCL code or extend an existing class. This can be worked around currently by writing new implementations in Java.