Planet Smalltalk

August 17, 2018

James Foster - Garbage Collection and Blocks

A question on the GLASS mailing list raised some interesting questions about garbage collection and persistent executable blocks. Some objects, such as instances of SortedCollection, may contain a reference to an executable block and this persistent reference may be difficult to update and may hold references to other objects that otherwise could be removed by the garbage collection process.

Simple vs. Complex Blocks

The first issue raised by the question is the distinction between a “simple block” and a “complex block.” In Smalltalk a block may reference variables outside the block and, if it does so, then the virtual machine needs to create a more complex data structure to capture the referenced objects (making it a “complex” block). If the block does not reference any variables outside its immediate scope (beyond the block arguments and block temporaries), then the virtual machine can typically use a much simpler implementation (making it a “simple” block).

Because of the extra overhead, complex blocks tend to take more room and be slower to execute. Thus, a common performance tuning activity is replacing complex blocks with simple blocks when possible, and this can occur in application code as well as vendor-supplied libraries. For example, in GemStone/S 64 Bit version 2.x, the implementation of SortedCollection>>#’addAll:’ is essentially the following:

aCollection do: [:each | self add: each].

The problem with this implementation is that the block references self, making it a complex block. In version 3.x the implementation changed (influenced in part by Paul Baumann’s work), and the code is essentially the following:

aCollection accompaniedBy: self do: [:me :each | me add: each].

The block in this code is a simple block since it does not reference self (or anything outside the block), and performance improved.

While this is all very interesting (and in some cases quite useful), I think that the underlying garbage collection problem is not really with simple vs. complex blocks, but with something else.

Class References in Blocks

A code block in a method will contain a reference to the method and thus to a class (or metaclass for a class-side method). Once the code block is persistent, there is a hard reference to the class (and its class variables, class instance variables, and pool variables). Changes to the class schema will create a new “version” of the class but the old version will remain and be referenced by the code block. Even if the old class version is removed from the ClassHistory and all instances of the old version are migrated to the new version, until the code block is replaced in the persistent object, there will be a hard reference to the old class version and its space cannot be reclaimed by the garbage collection process.

To see how this works consider the method SortedCollection>>#’_defaultBlock’:

| block |
block := SortedCollection new _defaultBlock. "anExecBlock2"
block _debugSourceForBlock. "'[ :a :b | a <= b ]'"
block method. "aGsNMethod"
block method isMethodForBlock. "true"
block method inClass. "SortedCollection"

Note that this situation exists whether or not the block is simple or complex and whether or not the block comes from an instance-side method or a class-side method. Thus, this is an orthogonal discussion or a unique concern.

Alternatively, note how an equivalent block can be created by evaluating a String, but does not contain a reference to a Class:

| block |
block := '[ :a :b | a <= b ]' evaluate. "anExecBlock"
block _debugSourceForBlock. "'[ :a :b | a <= b ]'"
block method. "aGsNMethod"
block method isMethodForBlock. "true"
block method inClass. "nil"

So, as suggested one could strip the class reference with the following code:

^ aBlock _sourceString evaluate

Alternatively, one could avoid the private method (#’_sourceString’) by making the String explicit:

^ '[ :a :b | a <= b ]' evaluate

While this avoids the private method, it hides the code in a string making it much more difficult for tools to recognize that this is code (and catch compile errors, support senders/implementors, provide for refactorings, etc.). Further, each of these approaches will create a new instance each time it is called, creating unnecessary objects.

As Dale noted in the email chain referenced above, we could modify the compiler so that a block did not know the class in which it was created. This might improved the garbage collection situation, but would make it more difficult to debug code and track a block back to its source. And, of course, you would need to wait till that feature was added to the product.

One way to address these issues is to create a new class with no instance variables (so that the schema would never change) and use class-side methods to return the desired blocks. The method that would otherwise hold the code block would use a level of indirection to return the actual block. If a code block needed to change, you would create a new class-side method in the special class and edit the indirecting method (so that references to the old code block could be found and modified). The original method would remain as long as there were references to it.

At the cost of a level of indirection (and reduced encapsulation), this gives you actual source code that can be recognized by tools, a single instance, and no stray references from the class (since there is only one class version).

[Note: I found this in “Drafts” and decided to publish it even though the original question was a couple years ago.]

 

James Foster - ESUG Presentation

August 16, 2018

Pharo Weekly - Iceberg 1.2.2

Iceberg 1.2.2

# Bugfixes

#961 Authentification error while connecting with HTTPS
#965 Walkback – #nextChildNodeStartingFrom:suchThat:ifNone: committing selected code to branch (repo with ./dev/src)
#967 Merging a Commit that does not have Smalltalk Code
#962 DNU when loading with metacello and gitlocal

# Cleanups

#972 use instanceSide/classSide instead of other API
#964 Rename “Add Local Repository” into “Import from disk”

 

The iceberg team

August 14, 2018

Smalltalk Jobs - Quality Assurance Analyst, Glasgow, UK

The Kapital project (VisualWorks and GemStone) seeks a test analyst to perform test execution and comparison, defect management, problem solving, debugging, coding, delivery of test results, and active involvement in team discussions and the agile process.  They want experience of the full software test lifecycle, and of agile processes.  Knowledge of Smalltalk, Unix, OO testing and/or the financial domain is a plus.

Cincom Smalltalk - Tutorial Tuesday: How to Create a Simple ‘Hello World’ Application

In this week's Tutorial Tuesday, we look at Core Browser Usage with Cincom Smalltalk™. In this tutorial, we demonstrate to students of Smalltalk, a step-by-step walk-through of using the browser to create something simple such as a 'HelloWorld' application.

The post Tutorial Tuesday: How to Create a Simple ‘Hello World’ Application appeared first on Cincom Smalltalk.

August 13, 2018

Pharo Weekly - [Ann] … with parent lookup

There are cases where you want to have an environment/dictionary that asks its parent when a key is not locally defined. For this you can use a PropertyEnvironment.

https://github.com/Ducasse/Containers-PropertyEnvironment

100% test coverage of a good and simple semantics.

S.

Pharo Weekly - Esteban’s log

Hello!

This is my weekly ChangeLog, from 6 August 2018 to 12 August 2018.
You can see it in a better format by going here: http://log.smallworks.eu/web/search?from=6/8/2018&to=12/8/2018

ChangeLog
=========

7 August 2018:
--------------

*    I've been working on a new ODBC driver for Pharo, made on UFFI and Garage. 
    
    Sadly, I cannot take the existing older ODBC driver as base because it was depending too much 
    on old FFI structure. Also, it didn't have any test or example so it was hard to take as 
    inspiration (too many differences to tacle).
    
    Anyway, the new ODBC driver will come soon(tm), in the mean time I needed to fix some issues on 
    UnifiedFFI: 
    
    * [case: 22287](https://pharo.fogbugz.com/f/cases/22287)
    * [case: 22300](https://pharo.fogbugz.com/f/cases/22300)
    
    This fixes some missing/incorrect parts on UFFI: first one adds a special handling for +size_t+ 
    types (needed because they behave differently in different platforms/architectures). And the second 
    fixes a problem when returning +enum+ values.

August 12, 2018

Smalltalk Jobs - Smalltalk Jobs – 8/12/18

  • Bangalore, IndiaSoftware Engineering (Job ID 180054169) at J.P. Morgan
    • Required Skills:
      • 5-12 years years of experience
      • Educational qualification: Bachelor degree/Master degree in engineering preferably in computer science/Information technology.
      • An understanding of an object oriented programming language and their underlying principles.
      • Excellent analytical, problem solving and organizational skills and ability to work independently.
      • Understanding of software skills such as business analysis, development, maintenance and software improvement.
      • Should have enthusiasm for increasing the knowledge of financial markets and products.
      • Willingness to adopt to an agile development process.
    • Wanted Skills:
      • Java
      • Python
Good luck with your job hunting,
James T. Savidge

View James T. Savidge's profile on LinkedIn

This blog’s RSS Feed

August 10, 2018

Pharo Weekly - HDFS for Pharo :)

Hello,

I would like to share one of my projects that I am working on in my PhD.
Since I am working on Big Data I wrote a library to access the Hadoop Distributed File System (HDFS).
We implemented it as a FileSystem in Pharo, using the webHDFS API of HDFS to access the files.
With this API you can browse the distributed file system and create/modify/delete directories and files.
Here is the git repository:
Documentation is in the readme.
Ciao,
Matteo

August 09, 2018

Cincom Smalltalk - Student Project Creates an Adaptable and Flexible Smalltalk Programming Environment for the Visually Impaired

At Universidad Nacional de Quilmes in Buenos Aires, Argentina, two students, along with the backing of their professors, elected to tackle a challenge that was affecting their visually impaired classmates: […]

The post Student Project Creates an Adaptable and Flexible Smalltalk Programming Environment for the Visually Impaired appeared first on Cincom Smalltalk.

August 08, 2018

Cincom Smalltalk - Who Should Use the Academic Personal Use License of Cincom Smalltalk™?

The Cincom Smalltalk Academic Personal Use License (APUL) is available to students, professors or teachers wanting to use Smalltalk for educational purposes and academia.

The post Who Should Use the Academic Personal Use License of Cincom Smalltalk™? appeared first on Cincom Smalltalk.

August 07, 2018

Pharo Weekly - About Iceberg design

Hi,

I'll write down some of the reasons of the project's design, like that I can afterwards copy paste it in the wiki :).

First, this design did not came up from an egg. We worked on it for about two months. And it is thought to be backwards compatible and manage lots of metacello particularities. It may have things that are perfectible, sure, so let's discuss it.

One of the main problems we saw in metacello, and that Iceberg inherited, was the "source subdirectory" thing. This source directory had to be specified in the CLIENT, meaning that every time we clone a repository we should know by heart the directory chose by its developer. Moreover, we lack a standard way to do it, so everybody does as he feels (root directory, src, source, repository, mc....).

This has some bad consequences:
 - once a repository is referenced by some other project, it is more
complicated to change its source directory. Imagine that tomorrow we set as standard that all git repos should have the code in src. Then voyage should change. And all its clients too.
 - Making a typo in the code subdirectory means sometimes super ugly errors from metacello that are difficult to debug and understand (e.g., "Cannot resolve BaselineOfMetacello WTF")

Moreover, there was another problem that people started stumbling on: the fact that iceberg got confused sometimes thinking that an empty project was in filetree (to keep backwards compatibility with projects without a .properties).

So we decided that for this release we wanted to revert a bit that
situation. Think object: let's put the meta-data used to interpret a
project's structure inside the project itself.
The idea is that:

 - each project should contain both a .project and a .properties file. The first can contain arbitrary project meta-data (such as the source directory). The second contains the cypress properties, which are needed to correctly interpret the code inside the source directory.
 - a project without a .project file is an old project and cannot be
interpreted, because we don't know the source directory
 - a project without a .properties file is an old project and is by default transformed in a project with a #filetree properties file
 - an old project cloned from iceberg detects the missing .project file and gives the user the opportunity to declare it (and then commit it explicitly)
 - an old project cloned and loaded from a Metacello expression defining a source directory will honnor the source directory defined in the Metacello expression (for backwards compatibility, and we have ~500 tests about this).

# About defaults values / forcing the user to define a project

First, notice that even when the repositories you load are just marked as "dirty".
This is because in memory we add a project to your repository. But you're not forced to commit it.Actually, you can still load packages and baselines from that repository without committing.

This is in line with Iceberg's "explicitness". We try to not do any
destructive operation without asking the user first (that's why we have several preview windows for pushing, pulling, checkout, merge..., and why
contrastingly with monticello we show the committed changes on the commit window...). So, instead of transparently "adding the file" we have decided to modify the project in memory and let the user the responsibility to commit that file.

If there's a drawback, is that the repository is marked as dirty. Which is a bit noisy, yes, but still I think it's not so bad compared with the previous drawbacks.
To solve this, we could have some default values, yes, and only mark it as dirty if the project does not follow the default value.
This could work, but right now all projects use different names for their source directories.
So the question is, what would be a good default? I'd like to use 'src' since this is short, well known and less alien (all these in the sense that we do not lose anything and we have a lot to gain by using it). However, not much repositories use 'src' so it will still produce a lot of "noise"...

But still! Committing that file is a one-time operation. Once people fix their repositories adding the project meta-data, you will not see them dirty anymore. So we can see this as a transition noise too...

Of course, new ideas are welcome. I'll let Pablo and Esteban add their points of view on this too.
Guille

Pharo Weekly - New Iceberg Version 1.2.1

https://github.com/pharo-vcs/iceberg/releases/tag/v1.2.0 +
https://github.com/pharo-vcs/iceberg/releases/tag/v1.2.1]
Thanks to all brave users, issue reporters, and contributors :).

This version includes the implementation of projects.
Projects are a way of defining basic metadata of the repository.
Now, this metadata just includes the source directory.

This means that people do not need anymore to provide ALL THE TIME the source directory.
Instead, every repository includes a project file that provides it.
Iceberg will guide people to create the given file. This file is managed by Iceberg and people should not touch it from the outside or accept the consequences :).

This version is integrated in the latest Pharo 7 images.

#New Features

 - #866 Introduce first version of Projects

#Infrastructure

 - #870 Improving tests of Metacello Integration
 - #903 Split basic tests from metacello tests in CI
 - #914 Sync Wiki with documentation directory automatically
 - #934 Manually check metacello integration dialogs
 - #935 Try to refrite the metacello integration tests.
 - #940 Installation in new Pharo should also bootstrap pharo repository

#Enhancements

 - #675 The History of a Method in Calypso should show a progress bar.
 - #788 Show progress during network operations (fetch,push, ...) Libgit.
 - #875 Tonel plugin does not delete .filetree Migration
 - #897 Update to OSSubprocess 1.0.1
 - #911 Repair Checkout branch should appear in "no project found"
 - #933 Fix Edit repository dialog
 - #939 IceInteractiveErrorVisitor duplicates IceTipInteractiveErrorVisitor
 - #944 Extract pharo repository bootstrap code into iceberg

#Bug Fixes

 - #828 Convert sources to tonel raises an Exception
 - #839 Infinite loop in IceGitLocalRepositoryType if the path is wrong
 - #849 VM crash while saving credentials Credential Manager
 - #851 .properties file is not create if project is imported and not
cloned.
 - #869 Error msg after an http timeout is unreadable
 - #873 Error with credential provider Credential Manager
 - #874 The integration with Metacello does not work when there is a src
directory, but not project file.
 - #880 Putting "." in project src field gives dnu
 - #884 Edit Project Dialog tries to select 'src' folder as default, but
does not handle if it does not exists
 - #886 Edit Project Dialog does not allow to select the root of the
repository as source directory
 - #888 Could not locate repository does not have subdirectory anymore.
 - #889 Loading an unborn project through metacello does not work
 - #894 GitHubAPI fails when the API responds with a 204 No Content
 - #901 I get a DNU projectName....
 - #902 Edit project metadata does not detect default format
 - #918 Cloning pharo from a sync'ed repository does not correctly show
dirty packages
 - #928 Pull request cancel
 - #930 Changed ivar/slot name in stateful trait not recognized as a change
 - #931 DNU when trying to unload an Iceberg pkg where underlying Pharo pkg
has been removed
 - #932 Pharo repository forgets packages
 - #938 Do not catch assertion failures
 - #941 Iceberg pre-installed repository has wrong repair action
 - #946 Fixing Metacello Integration Tests
 - #948 Cloning from github creates an invalid remote
 - #950 Iceberg v1.2.0 breaks projects Metacello Integration bug
 - #951 New project window should be coherent on the vocabulary UI
enhancement
 - #953 Make remote request anonymous enhancement
 - #952 Cannot Clone Pharo Repository Pharo plugin bug
 - #955 Repair actions for repositories with fetch required are wrong UI bug

-- 
Pablo Tesone.
tesonep at gmail.com

Cincom Smalltalk - Tutorial Tuesday: What is the Cincom Smalltalk System Browser?

In this tutorial, we demonstrate the System Browser, introducing the various panes of the browser, what they are showing, and how the tool is used.

The post Tutorial Tuesday: What is the Cincom Smalltalk System Browser? appeared first on Cincom Smalltalk.

August 02, 2018

Cincom Smalltalk - Semiconductor Customers Reach Market Faster with Smalltalk-Based ControlWORKS

Rudolph Technologies Helps Semiconductor Customers Reach Market Faster with Cincom Smalltalk-Based ControlWORKS Rudolph Technologies, Inc. is a software development and integration services company for the semiconductor industry. Rudolph delivers advanced process control, equipment control, […]

The post Semiconductor Customers Reach Market Faster with Smalltalk-Based ControlWORKS appeared first on Cincom Smalltalk.

August 01, 2018

Cincom Smalltalk - Hidden Gems: DomainMaster BONUS – Pattern1

A more detailed walk-through of the DomainMaster using Pattern1 for those who want more information on using the framework.

The post Hidden Gems: DomainMaster BONUS – Pattern1 appeared first on Cincom Smalltalk.

July 28, 2018

Pharo Weekly - Sharing some discussions

To give you a feel of the friendliness of the Pharo community, here is a part of a discussion:


Hi Offray,

> On 27 Jul 2018, at 12:39, Offray Vladimir Luna Cárdenas <offray.luna at mutabit.com> wrote:
> 
> Hi,
> 
> I was ready to show a friend the Pharo web capabilities with the
> classical "myString asUrl retrieveContents", but the friend gave me a
> url that contains non Latin characters[1] and then I got an
> ZnInvalidUTF8 error.
> 
> [1]
> http://www.bidchance.com/freesearch.do?&filetype=&channel=&currentpage=1&searchtype=zb&queryword=%BF%A6%CA%B2&displayStyle=&pstate=&field=&leftday=&province=&bidfile=&project=&heshi=&recommend=&field=&jing=&starttime=&endtime=&attachment=
> 
> How can I process web addresses in Pharo that contain non latin
> characters like the one in [1]?

I am on holiday, so I cannot go too deep into this, but AFAIU the URL is wrong (or it assumes a specific context with a non-standard encoding).

In a URL's query part, non-ASCII data is first UTF-8 encoded, then percent encoded (this is the modern way).

I don't read Chinese, so it is hard to infer much from the original site, but I am assuming the search is for '喀什', a city called Kashgar, https://en.wikipedia.org/wiki/Kashgar_(disambiguation).

The string in question can be written as (to avoid copy/paste problems):

  String with: 21888 asCharacter with: 20160 asCharacter.

The encoding in a URL has to be:

  ZnPercentEncoder new encode: (String with: 21888 asCharacter with: 20160 asCharacter).

This gives us for example the following URL:

  'https://www.google.com/search?q=%E5%96%80%E4%BB%80' asUrl.

Which parses OK and contains the correct encoded string (decoded in the URL object):

  'https://www.google.com/search?q=%E5%96%80%E4%BB%80' asUrl queryAt: #q.

If you copy/paste that URL in your browser it should resolve to stuff about Kashgar.

Obviously the website www.bidchance.com does something else (non-standard ?).

HTH,

Sven

> Thanks,
> 
> Offray

July 25, 2018

David Buck (Simberon) - Smalltalk contract work

Looking forward, I'll have some time available between now and the end of the year to take on other projects.  If anyone is interested in contracting some work to Simberon let me know.  Simberon specializes in Smalltalk software development (VisualWorks, ObjectStudio, VA Smalltalk and GemStone).  Services include:


  • Version upgrades
  • Custom software development
  • Tracking down difficult bugs
  • Mobile application development on Android and iOS in VisualWorks Smalltalk
  • Instructor-led Training
    • Introduction to Smalltalk
    • Advanced VisualWorks Topics
    • Design Patterns
    • Improving Object Oriented Design
Contact me at info@simberon.com if there are any services you would like.

David Buck (Simberon) - Sea Turtle Rescue

I've been a bit quiet about my game recently.  It's not because I'm not working on it - I am.  It's that I'm changing the game around so much that I have to get my head around it.

I'm in the process of transforming the game to a new theme and new title.  I've hired an animator and graphics artist to do artwork for me.

The new game will be "Sea Turtle Rescue". The goal of each level of the game is to hatch sea turtle eggs and guide the sea turtles into the ocean.  The basic mechanics will be the same as HexSolve but the graphics and animation will all change.

Tiles in the board will become tiles covered with sand.  The target will become a sea turtle egg.  When you make a sequence (a path) from 1 up to the tile with the egg, the egg will hatch and a sea turtle will emerge.  The sea turtle will shuffle down the path you built (in reverse order: eg. 4, 3, 2, 1) until it gets to the 1 tile where it will drop into the ocean below.

I'll be adding sound and music to the game to add an extra ambiance.

I like the new theme much more than the strict mechanical puzzle theme of HexSolve.  It gives a nice purpose for the game and an interesting theme.  I'll try to keep you posted as we make progress.

July 23, 2018

Pharo Weekly - Cryptography on github

After several attempts to solve the Cryptography package problems over the years I decided to move it on my own to github.

What I did:

- researched all authors and used the git migration tool to get the package from smalltalkhub to github 
- released a version 0.1 that should be exactly the same as the code on smalltalkhub for people that want to change
- fixed an occurrence of IfNotNilDo: in the Cryptography package to make it load in pharo7
- added a metacello baseline
- added a group „all" that loads everything like it is now with one package
- added travis files and enable travis checks for pull requests
- released a version 0.2 that contains the original code plus travis and metacello
- Started to cut off the ASN1, PKCS12 and X509 classes in separate packages
- Added to each new package a -Tests package containing tests
- constructed all dependencies in the baseline
- added a core group that loads the now slimmed down package solely

I must say this was really great with the help of promote-demote package tag functionality and the dependency browser. The only thing missing is kind of a tool to construct the metacello baseline. I miss Versionner here.

What I didn’t do:

- checking all the other packages in the repo. There are packages with old style ffi calls and things that seem to be squeak dependent.

I hope with the time and people’s complaints we can figure out what is obsolete and what needs to be adjusted.

The repository is now at

https://github.com/zweidenker/Cryptography <https://github.com/zweidenker/Cryptography>

but I’m happy to move it to a better place if someone has an idea. 

Pull requests and tickets are welcome.

Hope you like it,

Norbert

July 22, 2018

Smalltalk Jobs - Smalltalk Jobs – 7/22/18

  • Bend, OregonSoftware Engineer (m/f) for
    Equipment Integration (EI)
    at SYSTEMA

    • Required Skills:
      • A degree in Computer Science / Information Technology / Software Engineering / Electrical Engineering.
      • Professional experience in high-tech manufacturing
      • Familiarity with SECS/GEM, MES, SOA, MOM, AMHS, APC, and SPC in semiconductor, electronics or photovoltaic manufacturing
      • Possess high interest in Computer Integrated Manufacturing (CIM) or Equipment Integration
      • Have a passion for system design and programming in manufacturing environments
      • Knowledge in C/C++, Java, Smalltalk and Delphi
      • Willing to occasionally travel domestic and international
      • Worked with relational database design, SQL development, version control
      • Automated software production and test systems
      • JEE
      • Eclipse
      • Microsoft.NET
Good luck with your job hunting,
James T. Savidge

View James T. Savidge's profile on LinkedIn

This blog’s RSS Feed

Pharo Weekly - New success story: LawTracker

Here is a new success story around Pharo.

http://pharo.org/success/LawTracker

Do not hesitate to send to us your success stories.

July 20, 2018

Pierce Ng - MelcGraph

MelcGraph is a graph algorithm library by Ciprian Teodorov. I've updated the package to handle the deprecation of #name, using 'label' in place of 'name' as inst-var and in selectors. Thanks Ciprian for giving me commit access to the repo.

Pharo Weekly - Thermite

Hello,

I am finally releasing an initial public version of Pharo Git Thermite, a tool that I am developing as part of my master thesis for visualizing Monticello and Git commits, for Pharo and Python:

GitHub Page with sources/documentation/issue tracker:
https://github.com/ronsaldo/pharo-git-thermite

Short video examples:
- Monticello Visualization; https://youtu.be/02CUHBmm-K8
- GitHub pull request: https://youtu.be/f196btLfYxM
- Local git commit: https://youtu.be/LCHTiJ4nx3g

Feedback form:
https://docs.google.com/forms/d/e/1FAIpQLSeir6VlE3bR78oRsNAp9eHLkUn2Q016wEliOJN7tFlTmYFi8w/viewform?usp=sf_link

Best regards,
Ronie

July 18, 2018

Cincom Smalltalk - Smalltalk Digest: July Edition

In this edition, we look at the value of the Resolutions Newsletter, the next step in using Cincom Smalltalk with MongoDB and a hidden gem about using IEX API.

The post Smalltalk Digest: July Edition appeared first on Cincom Smalltalk.

Cincom Smalltalk - Salta, Argentina to Host Smalltalks 2018!

The 12th Smalltalks Conference (Smalltalks 2018) will take place in Salta, Argentina on October 31 through November 2, and workshops are also being planned at the same location on October […]

The post Salta, Argentina to Host Smalltalks 2018! appeared first on Cincom Smalltalk.

July 17, 2018

Cincom Smalltalk - What is the Cincom Smalltalk Resolutions Newsletter and Why is it a Valuable Tool for Customers?

The Resolutions Newsletter lets customers know what’s going on with the product since the last release so they can see what resolutions are available.

The post What is the Cincom Smalltalk Resolutions Newsletter and Why is it a Valuable Tool for Customers? appeared first on Cincom Smalltalk.