How to Program/en

Aus expecco Wiki (Version 2.x)
Zur Navigation springen Zur Suche springen

Introduction to Programming in expecco[Bearbeiten]

The following relates to "Programming in Smalltalk or the builtin JavaScript within expecco" - it is not relevant for the other (scripting and bridged) languages. We assume, that if you program in Python, you will already know Python. But if you want to use the full power of the underlying Smalltalk machinery, you should read the following.

Before you start programming your own elementary actions, please read this document, which describes how program code is handled in expecco. Unless you are familiar with the dynamics of a Smalltalk development environment, some of it may be unknown to you. You will have more fun and be more productive, if you know the power of the tools.

Although Smalltalk and the builtin Javascript use a different syntax, they are semantically equal, and both languages are compiled into the same bytecodes for the underlying virtual machine (which is the Smalltalk/X VM). Information regarding syntax and the mapping of language constructs is found via the links below.

See "JavaScript Language Syntax" and "Smalltalk Language Syntax" for the syntax.

Find Functions by Example[Bearbeiten]

Method Finder searching bit operations

Expecco includes a very powerful tool called "Method Finder", to help finding operations by expected result. You have to give it input values and a desired result value, and it will search for operations which compute that value.

In other words, it answers the question:
"given an input A, which operation will give me X as output?",
or "given inputs A,B,C, which operation will give me X?".

  • For example, if you don't know how to perform a bitwise mask operation in Smalltalk, open a method finder, enter 0b10101010 as input1, 0b11110000 as input2 and the desired result 0b10100000 as expected result value.

The finder will answer all operations which generate that outcome. The result list's popup menu contains an item "Senders" which searches where this code is used in the system, to find usage examples quickly.

  • As another example, if you need a function to strip spaces from a string, enter ' foo. ' (with spaces and quotes) as input and 'foo' (without spaces) as result.
  • And, if you have to split a string separating words by commas, enter 'a,b,c' (with quotes) as input1, the separator ',' as input2 and #('a' 'b' 'c') (an array constant with 3 strings in it) as expected result.

The method finder is opened via the "Extras" → "Tools" → "Method Finder" menu item.

A similar tool called "Action Finder" is provided to find action blocks in the diagram editor.

Executing Code Fragments[Bearbeiten]

Most of the tools inside expecco (especially the editor, notepad, data inspector and debugger) are able to execute code fragments.

To do this, select the piece of code to be executed and choose one of the "DoIt", "PrintIt" or "InspectIt" menu functions. If no text is selected, the full cursor text line is evaluated. The ESC-key selects everything from the start of the line up to the current cursor position.

"DoIt" will simply execute the code, "PrintIt" will paste the returned value and "InspectIt" will open a data inspector on the result.

The syntax depends on the context: in an elementary action's code editor, it will be the selected language (1), in a workspace, it is selectable via a menu setting, in a debugger, it will be the language of the function being shown, in an inspector it is usually Smalltalk syntax.

1) Currently, this is not implemented for all external languages (Python, NodeJS, etc.). However, the internal languages (Smalltalk and JavaScript) do support this.


To get a feeling for this, try the following:

  • open a workspace (Mainmenu: "Extras" → "Tools" → "Notepad")
  • select Smalltalk syntax (Workspace menu: "Workspace" → "Smalltalk")
  • enter a piece of Smalltalk code (for example: "1024 hexPrintString")
  • select this code
  • apply "PrintIt"
  • the text "400" (which is the hexadecimal representation of the integer 1024) will be pasted at the text cursor position.

Try the same with the code fragment: " 'hello world' copyTo: 5 ".

Opening a Notepad (also called "workspace")[Bearbeiten]

Opening workspace.png

Evaluating a code fragment[Bearbeiten]

Workspace printit.png


If you prefer JavaScript syntax, change it via (Workspace menu: "Workspace" → "JavaScript").
Of course, you have to enter "hello world".copyTo(5) then, to get the above result.

Inspecting Data[Bearbeiten]

Now do the same, but apply the "InspectIt" menu function instead.
An inspector window will appear, which shows the resulting object (i.e. the "Return value" of the expression). Here, a string object containing the first 5 characters is inspected:

Inspector tool.png

The inspector's left subview presents the internal slots of the object plus some meta-info (class, size and useful representations) as a list. When an item is selected, that slot's value is shown in the right subview. This is another workspace (so "DoIt", "PrintIt" etc. are again possible there).

Double-click on a left entry navigates into it. Use the back-button to see the previous object again.

Hot-Swapping Code[Bearbeiten]

One of the coolest feature of expecco is its hot-swap capability. Code can be edited and recompiled while the program (test) is running, without a need to stop the execution. However, it is not possible to hot-swap the one function which is currently being executed: it has to be either returned from, or restarted after a change. When an elementary function's code is changed, the new version will be activated with the next call (i.e. when the action is next activated).

Hot Swap Example[Bearbeiten]

To demonstrate the above, create a Smalltalk elementary block (give it any name, such as "Testblock"), give it one input and one output parameter:
Defining TestBlock scheme.png

and define its code as:

execute
    out1 value:(in1 value * 2)

if you prefer JavaScript, the code would be:

execute() {
    out1.value( in1.value() * 2);
}

Then create a compound action block (say "Testblock-Runner"), and drop the above TestBlock-action into its network, freeze its input value with some number, add a "Transcripter" which shows the output and add a delay step. Connect the delay step to be executed sequentially after the Testblock:

Defining TestRunSetup1.png

Now switch to the "Test/Demo" tab, add a loop-counter pin to the test step with a value of (say 100):

Defining TestRunSetup2.png

Now, run it.
As you can see, the running network outputs the input value multiplied by 2 once a second.

Let it continue to run, while opening another expecco window, and navigate to your test block there. Change the code to multiply by 3 instead of 2, and "accept" it. Go back to the still running test-loop and notice that the generated output values have changed.

Congratulation: you have changed the code of an action, while the test is running.

Programming "in the Debugger"[Bearbeiten]

You can also change code inside a debugger. To try, place a breakpoint on a code line in the above elementary action, then, when in the debugger make a change to the code. For example, add a debug print line such as:

Transcript showCR:'hello'.

and accept the change (in the debugger).
Finally, press "Continue", "Restart" or "Abort".

  • Continue - If you continue, the rest of the (old) code will be executed, and the change becomes effective when the action is invoked the next time.
  • Restart - If you restart, the action will be restarted from the beginning, now executing your changed code.
  • Abort - this will cancel the current block or test execution; the change will be effective when you run again

Asking ChatGPT?[Bearbeiten]

ChatGPT can help you to program elementary actions in Smalltalk. However, be aware that it is unlikely to find a "good" solution. So some verification is usually needed.
As an example, here is a transcript of a little ChatGPT (3.5) conversation:

User>

  I am programming in the smalltalk language. 
  I have a collection of strings. How can I find the longest?

ChatGPT>

  In Smalltalk, you can find the longest string in a collection of strings using the following steps:

  * Initialize a variable to hold the longest string found so far. Let's call it 'longestString' 
    and set it to an empty string or nil.

  * Iterate over the collection of strings using a loop or a higher-order function like do: or detect:.

  * For each string in the collection, compare its length with the length of the longestString using the size method.

  * If the current string is longer than the longestString, update the value of longestString to the current string.

  * After iterating over all the strings, the longestString variable will hold the longest string in the collection.

 Here's an example code snippet that demonstrates this approach:

   | strings longestString |
   strings := #('Hello' 'World' 'Smalltalk' 'Programming' 'Language').

   longestString := strings first.
   strings do: [:eachString |
       (eachString size) > (longestString size) ifTrue: [
           longestString := eachString
       ]
   ].

   Transcript show: 'Longest string: ', longestString.
 In this example, the collection of strings is defined using an array literal 
 (#('Hello' 'World' 'Smalltalk' 'Programming' 'Language')). 
 You can replace it with your own collection.

 The code iterates over each string in the collection using the do: method. 
 It compares the length of each string with the length of the longestString and updates it if a longer string is found.

 Finally, the longest string is printed to the Transcript using Transcript show:. 
 You can modify this part to suit your needs, such as storing the longest string in a variable or displaying it in a different way.

User>

  can you provide an alternative program which uses the inject:into: message?

ChatGPT>

  Certainly! Here's an alternative program that uses the inject:into: message 
  to find the longest string in a collection:

    | strings longestString |
    strings := #('Hello' 'World' 'Smalltalk' 'Programming' 'Language').

    longestString := strings inject: '' into: [:eachString :currentLongest |
        eachString size > currentLongest size ifTrue: [eachString] ifFalse: [currentLongest]
    ].

    Transcript show: 'Longest string: ', longestString.

 In this version, we use the inject:into: message to iterate over the collection of strings and accumulate the longest string.
 The inject:into: message takes two arguments: an initial value ( in this case) and a block that defines how the accumulation should be performed.

 The block takes two arguments: eachString represents the current string being processed, and currentLongest represents the current longest string found so far. Inside the block, we compare the length of eachString with the length of currentLongest and return the longer string.

 The inject:into: message automatically iterates over each string in the collection and updates the currentLongest variable accordingly. Finally, the longest string is printed to the Transcript as before.

 Note that the inject:into: message is a powerful higher-order function in Smalltalk that can be used for various accumulation tasks. It's a concise and elegant way to find the longest string in this case.



Copyright © 2014-2024 eXept Software AG