Pharo-users
By thread
pharo-users@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
June 2017
- 100 participants
- 622 messages
Re: [Pharo-users] How to use uFFI with String
by Ben Coman
Cool. Looks good.
cheers -ben
On Wed, Jun 7, 2017 at 2:20 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
wrote:
> Hi ben
>
> Yes I changed it :)
> Stef
>
> On Mon, May 29, 2017 at 10:16 AM, Ben Coman <btc(a)openinworld.com> wrote:
> > On Mon, May 29, 2017 at 7:24 AM, horrido <horrido.hobbies(a)gmail.com>
> wrote:
> >> I don't use GitHub. I've never used GitHub. I don't know how to use
> GitHub.
> >>
> >> I looked at making a pull request and I was totally stymied. "Clueless"
> >> doesn't even begin to describe how I felt.
> >
> > Everyone starts there. Its a useful skill to have, so if you are
> > interested to learn, here's a quickstart guide...
> > (Note since its a text file, we are shortcutting so you don't even
> > need git on your local machine)
> > 1. Click on this link.
> > https://github.com/SquareBracketAssociates/UpdatedPharoByExample/blob/
> master/Morphic/Morphic.pier
> > 2. Click the <Fork> button in the top tight, then browse to
> > "Morphic.pier" in your fork.
> > 3. To the right of the <Raw/Blame/History> buttons, click the <Pencil>
> > button to edit the file.
> > 4. After editing, at the bottom select "Create a new branch for this
> > commit and start a pull request"
> > and enter commit title, comment and new-branch-name to reflect your
> > contribution. Click <Propose file change>
> > 5. Now looking at "Open a pull request", this is issuing a PR to your
> > own fork. We need to change to the upstream fork. At the top click
> > on "forked from SquareBracketAssociates/UpdatedPharoByExample" .
> > 6. Under "Your recently pushed branches" click <Compare & pull request>
> > 7. Check...
> > base fork: SquareBracketAssociates/UpdatedPharoByExample
> > base: master
> > head fork: YourName/UpdatedPharoByExample
> > compare: your new-branch-name
> > Review the diff, enter PR title and comment, then click <Create pull
> request>.
> >
> > If you have problems, try to catch me on Discord...
> > https://discord.gg/dKv4qR/KCKQSSt
> >
> > cheers -ben
> >
> > P.S. @Stef, btw, it looks like "the guidelines for contributing" is
> > out of date...
> > https://github.com/SquareBracketAssociates/
> UpdatedPharoByExample/blob/master/CONTRIBUTING.md
> > "This is a test to see if it makes sense to convert PharoByExample
> > into pier format."
> >
> >
> >>
> >>
> >> Ben Coman wrote
> >>> On Sat, May 27, 2017 at 9:15 PM, horrido <
> >>
> >>> horrido.hobbies@
> >>
> >>> > wrote:
> >>>> Yes, I did. I found it difficult to understand. It would be nice to
> have
> >>>> some
> >>>> clear examples in the documentation, for example, really simple and
> >>>> common
> >>>> situations such as a C function returning an integer in a
> >>>> passed-by-reference argument.
> >>>>
> >>>> Speaking of documentation, in "Pharo by Example 50," I found this
> >>>> statement:
> >>>>
> >>>>> (Recall that you should set halosEnabled in the Preferences
> >>>> browser.)
> >>>>
> >>>> However, nowhere else in the book is there any reference to
> halosEnabled
> >>>> or
> >>>> Preferences browser.
> >>>
> >>> Nice pick up. Now in Settings (in a fresh 60473 image), filtering on
> >>> "halo" shows only:
> >>> * Cycle both directions
> >>> * Encloses fullbounds
> >>> * Exhibits bounds
> >>> so the comment seems irrelevant
> >>>
> >>> and #halosEnabled & #halosEnabled: each have one implementor
> class-side of
> >>> Morph
> >>> with one sender from MorphTest each, and one sender from
> Morph>>addHalo:
> >>>
> >>> and "Morph halosEnabled" ==> true, so the statement seems unnecessary.
> >>> Would you like to contribute a pull request removing it?
> >>> https://github.com/SquareBracketAssociates/UpdatedPharoByExample/blob/
> master/Morphic/Morphic.pier
> >>>
> >>>
> >>>> Did you guys forget and leave out a chunk of the book?
> >>>
> >>> Its an evolutionary book originally from Squeak. It could well be
> >>> that some parts of the book have been cleaned
> >>> better than others to match Image changes. Thanks for reporting, and
> >>> even better if you can correct it.
> >>>
> >>> cheers -ben
> >>
> >>
> >>
> >>
> >>
> >> --
> >> View this message in context: http://forum.world.st/How-to-
> use-uFFI-with-String-tp4947890p4948512.html
> >> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
> >>
> >
>
>
June 7, 2017
Re: [Pharo-users] How to deploy headless app without changes and source files?
by Andreas Sunardi
Hi Stef,
I can't have changes file bundled with the tool because the tool is
installed in a centralized location in my network and multiple users will
run it. So the image is in a central location and read-only and so is the
changes file (if I must have a changes file). The tool is only a processor.
It does not need to keep/save its state.
Hence, I cannot have multiple users writing to that one and the same
changes file.
I'm trying to dissect the call chain to ChangesLog and try to cut it so
Pharo won't write to the changes file. I'm sure I should not do this. There
must be a better way.
On Tue, Jun 6, 2017 at 11:55 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
wrote:
> We started to work on making the system ready to stop using these files.
> There are two things.
> - the changes are a tape that logs what you are doing and right now
> the system is not done to accept not to log
> So I imagine that you can remove the changes file but then do not compile
> code.
> - I do not get the "so I can't have changes file bundled with the tool."
> you do not have a bat or script that launches the application that is
> somewhere in a folder where you have the vm and the image? you could
> have the changes file there.
>
> We are interested in your scenario because last year I got a guy
> working on making pharo silent. I do not know if its changes got
> integrated into pharo.
> This is really something that we want to have.
> - having sources and changes in a specific location
> - having no source and no changes (even if it means lose your code).
> - ...
>
> Stef
>
> On Tue, Jun 6, 2017 at 8:14 PM, Andreas Sunardi <a.sunardi(a)gmail.com>
> wrote:
> > Sorry to bring this up again. But it turns out that I had the image
> > directory writable by myself, so it created a new changes file. That's
> why
> > Pharo didn't complain about missing changes file. When I removed write
> > permission in the tool installation, Pharo gives error for not having or
> not
> > able to write to changes file.
> >
> > I guess I'm back to the problem how to deploy a tool without changes
> file. I
> > have multiple users that will be running this tool, which is installed
> in a
> > centralized site, so I can't have changes file bundled with the tool.
> >
> > On Mon, Jun 5, 2017 at 5:47 PM, Andreas Sunardi <a.sunardi(a)gmail.com>
> wrote:
> >>
> >> I had my changes and sources files in the bundle but has their write
> >> permission removed, and that causes the error. Simply deploying the tool
> >> without the changes file seems to fix it. Pharo5 doesn't complain if the
> >> changes file isn't there.
> >>
> >> However, without the sources file, I get this warning that pharo cannot
> >> locate the sources file. Including the sources file in the deployed
> tool is
> >> fine with me.
> >>
> >> So, I think that's my solution. Thanks!
> >>
> >>
> >> On Mon, Jun 5, 2017 at 5:07 PM, Andreas Sunardi <a.sunardi(a)gmail.com>
> >> wrote:
> >>>
> >>> I found this StackOverflow question:
> >>>
> >>> https://stackoverflow.com/questions/14737695/is-it-
> possible-to-deploy-a-pharo-image-without-changes-and-
> sources-files/14747328
> >>>
> >>> and this older forum thread:
> >>>
> >>> https://www.mail-archive.com/pharo-project@lists.gforge.
> inria.fr/msg21170.html
> >>>
> >>> I'm using Pharo5.0 and neither of these options is available anymore.
> >>> What is the new way to do this?
> >>>
> >>> --
> >>> Andreas Sunardi
> >>
> >>
> >
>
>
June 6, 2017
Re: [Pharo-users] How to deploy headless app without changes and source files?
by Stephane Ducasse
We started to work on making the system ready to stop using these files.
There are two things.
- the changes are a tape that logs what you are doing and right now
the system is not done to accept not to log
So I imagine that you can remove the changes file but then do not compile code.
- I do not get the "so I can't have changes file bundled with the tool."
you do not have a bat or script that launches the application that is
somewhere in a folder where you have the vm and the image? you could
have the changes file there.
We are interested in your scenario because last year I got a guy
working on making pharo silent. I do not know if its changes got
integrated into pharo.
This is really something that we want to have.
- having sources and changes in a specific location
- having no source and no changes (even if it means lose your code).
- ...
Stef
On Tue, Jun 6, 2017 at 8:14 PM, Andreas Sunardi <a.sunardi(a)gmail.com> wrote:
> Sorry to bring this up again. But it turns out that I had the image
> directory writable by myself, so it created a new changes file. That's why
> Pharo didn't complain about missing changes file. When I removed write
> permission in the tool installation, Pharo gives error for not having or not
> able to write to changes file.
>
> I guess I'm back to the problem how to deploy a tool without changes file. I
> have multiple users that will be running this tool, which is installed in a
> centralized site, so I can't have changes file bundled with the tool.
>
> On Mon, Jun 5, 2017 at 5:47 PM, Andreas Sunardi <a.sunardi(a)gmail.com> wrote:
>>
>> I had my changes and sources files in the bundle but has their write
>> permission removed, and that causes the error. Simply deploying the tool
>> without the changes file seems to fix it. Pharo5 doesn't complain if the
>> changes file isn't there.
>>
>> However, without the sources file, I get this warning that pharo cannot
>> locate the sources file. Including the sources file in the deployed tool is
>> fine with me.
>>
>> So, I think that's my solution. Thanks!
>>
>>
>> On Mon, Jun 5, 2017 at 5:07 PM, Andreas Sunardi <a.sunardi(a)gmail.com>
>> wrote:
>>>
>>> I found this StackOverflow question:
>>>
>>> https://stackoverflow.com/questions/14737695/is-it-possible-to-deploy-a-pha…
>>>
>>> and this older forum thread:
>>>
>>> https://www.mail-archive.com/pharo-project@lists.gforge.inria.fr/msg21170.h…
>>>
>>> I'm using Pharo5.0 and neither of these options is available anymore.
>>> What is the new way to do this?
>>>
>>> --
>>> Andreas Sunardi
>>
>>
>
June 6, 2017
Re: [Pharo-users] [ANN] Pharo 6.0 released!
by Stephan Eggermont
On 06/06/17 17:11, Esteban Lorenzano wrote:
> Dear World,
>
> The time has come for Pharo 6.0!
Yes! Well done!
Stephan
June 6, 2017
Re: [Pharo-users] is it related to Freetype or Athens?
by Stephane Ducasse
Hilaire
If I remember correcly, there is a bug in cairo so igor was sometimes
forced to change the font size multiplying a little
to force the plugin to react.
Stef
On Tue, Jun 6, 2017 at 7:33 PM, Hilaire <hilaire(a)drgeo.eu> wrote:
> Hi there,
>
> A Dr. Geo user on Ubuntu 64bits 16.04 got that buggy rendering of the
> canvas, then on some situation the rendering completely stop on a red
> screen, with a stack showing may be a zero divide error. I did not get
> access to the PharoDebog yet.
>
> Fonts on the screenshot is not right too. Could it be a mixed problem
> between FreeType and Cairo? Any first though on the issue welcome.
>
> Given the fact Dr. Geo is still based on Pharo3 and it works pretty fine
> on my old Ubuntu 12.07 derived system, it may be time to port the newer
> Pharo6.
>
> Congrats for the Pharo6 release.
>
> Hilaire
>
> --
> Dr. Geo
> http://drgeo.eu
>
June 6, 2017
Re: [Pharo-users] How to use uFFI with String
by Stephane Ducasse
Hi ben
Yes I changed it :)
Stef
On Mon, May 29, 2017 at 10:16 AM, Ben Coman <btc(a)openinworld.com> wrote:
> On Mon, May 29, 2017 at 7:24 AM, horrido <horrido.hobbies(a)gmail.com> wrote:
>> I don't use GitHub. I've never used GitHub. I don't know how to use GitHub.
>>
>> I looked at making a pull request and I was totally stymied. "Clueless"
>> doesn't even begin to describe how I felt.
>
> Everyone starts there. Its a useful skill to have, so if you are
> interested to learn, here's a quickstart guide...
> (Note since its a text file, we are shortcutting so you don't even
> need git on your local machine)
> 1. Click on this link.
> https://github.com/SquareBracketAssociates/UpdatedPharoByExample/blob/maste…
> 2. Click the <Fork> button in the top tight, then browse to
> "Morphic.pier" in your fork.
> 3. To the right of the <Raw/Blame/History> buttons, click the <Pencil>
> button to edit the file.
> 4. After editing, at the bottom select "Create a new branch for this
> commit and start a pull request"
> and enter commit title, comment and new-branch-name to reflect your
> contribution. Click <Propose file change>
> 5. Now looking at "Open a pull request", this is issuing a PR to your
> own fork. We need to change to the upstream fork. At the top click
> on "forked from SquareBracketAssociates/UpdatedPharoByExample" .
> 6. Under "Your recently pushed branches" click <Compare & pull request>
> 7. Check...
> base fork: SquareBracketAssociates/UpdatedPharoByExample
> base: master
> head fork: YourName/UpdatedPharoByExample
> compare: your new-branch-name
> Review the diff, enter PR title and comment, then click <Create pull request>.
>
> If you have problems, try to catch me on Discord...
> https://discord.gg/dKv4qR/KCKQSSt
>
> cheers -ben
>
> P.S. @Stef, btw, it looks like "the guidelines for contributing" is
> out of date...
> https://github.com/SquareBracketAssociates/UpdatedPharoByExample/blob/maste…
> "This is a test to see if it makes sense to convert PharoByExample
> into pier format."
>
>
>>
>>
>> Ben Coman wrote
>>> On Sat, May 27, 2017 at 9:15 PM, horrido <
>>
>>> horrido.hobbies@
>>
>>> > wrote:
>>>> Yes, I did. I found it difficult to understand. It would be nice to have
>>>> some
>>>> clear examples in the documentation, for example, really simple and
>>>> common
>>>> situations such as a C function returning an integer in a
>>>> passed-by-reference argument.
>>>>
>>>> Speaking of documentation, in "Pharo by Example 50," I found this
>>>> statement:
>>>>
>>>>> (Recall that you should set halosEnabled in the Preferences
>>>> browser.)
>>>>
>>>> However, nowhere else in the book is there any reference to halosEnabled
>>>> or
>>>> Preferences browser.
>>>
>>> Nice pick up. Now in Settings (in a fresh 60473 image), filtering on
>>> "halo" shows only:
>>> * Cycle both directions
>>> * Encloses fullbounds
>>> * Exhibits bounds
>>> so the comment seems irrelevant
>>>
>>> and #halosEnabled & #halosEnabled: each have one implementor class-side of
>>> Morph
>>> with one sender from MorphTest each, and one sender from Morph>>addHalo:
>>>
>>> and "Morph halosEnabled" ==> true, so the statement seems unnecessary.
>>> Would you like to contribute a pull request removing it?
>>> https://github.com/SquareBracketAssociates/UpdatedPharoByExample/blob/maste…
>>>
>>>
>>>> Did you guys forget and leave out a chunk of the book?
>>>
>>> Its an evolutionary book originally from Squeak. It could well be
>>> that some parts of the book have been cleaned
>>> better than others to match Image changes. Thanks for reporting, and
>>> even better if you can correct it.
>>>
>>> cheers -ben
>>
>>
>>
>>
>>
>> --
>> View this message in context: http://forum.world.st/How-to-use-uFFI-with-String-tp4947890p4948512.html
>> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>>
>
June 6, 2017
Re: [Pharo-users] How to deploy headless app without changes and source files?
by Andreas Sunardi
Sorry to bring this up again. But it turns out that I had the image
directory writable by myself, so it created a new changes file. That's why
Pharo didn't complain about missing changes file. When I removed write
permission in the tool installation, Pharo gives error for not having or
not able to write to changes file.
I guess I'm back to the problem how to deploy a tool without changes file.
I have multiple users that will be running this tool, which is installed in
a centralized site, so I can't have changes file bundled with the tool.
On Mon, Jun 5, 2017 at 5:47 PM, Andreas Sunardi <a.sunardi(a)gmail.com> wrote:
> I had my changes and sources files in the bundle but has their write
> permission removed, and that causes the error. Simply deploying the tool
> without the changes file seems to fix it. Pharo5 doesn't complain if the
> changes file isn't there.
>
> However, without the sources file, I get this warning that pharo cannot
> locate the sources file. Including the sources file in the deployed tool is
> fine with me.
>
> So, I think that's my solution. Thanks!
>
>
> On Mon, Jun 5, 2017 at 5:07 PM, Andreas Sunardi <a.sunardi(a)gmail.com>
> wrote:
>
>> I found this StackOverflow question:
>> https://stackoverflow.com/questions/14737695/is-it-possible-
>> to-deploy-a-pharo-image-without-changes-and-sources-files/14747328
>>
>> and this older forum thread:
>> https://www.mail-archive.com/pharo-project@lists.gforge.inri
>> a.fr/msg21170.html
>>
>> I'm using Pharo5.0 and neither of these options is available anymore.
>> What is the new way to do this?
>>
>> --
>> Andreas Sunardi
>>
>
>
June 6, 2017
Re: [Pharo-users] [Pharo-dev] [ANN] Pharo 6.0 released!
by Stephane Ducasse
Tx torsten.
New space is opening to us :)
On Tue, Jun 6, 2017 at 7:49 PM, Torsten Bergmann <astares(a)gmx.de> wrote:
> Dear friends,
>
> Yes - really an impressive release. With many cleanups and new treasures in the image - but also many
> shiny new/updated external packages and projects (like Roassal, Polymath, Calypso browser, ... to name just a few).
>
> Thanks to all who helped - especially to the ones who cared and also worked on the not so interesting but
> often hard to solve issues or boring but necessary parts or infrastructure.
>
> The new git integration in Pharo and the included Iceberg tool will allow us to work with services
> like GitHub, GitLab, BitBucket - even own local git servers (for instance setups using Gogs.io). We can now manage
> project resources beside code, commit several packages at once and branch and merge as necessary.
> This really rocks!
>
> Many thanks also to all the contributors of the OpenSmalltalk initiative - it is also impressive
> how much progress was done on VM side. Also thanks to the ones writing new books, articles and tutorials
> so other can learn and enjoy such a fantastic dynamic and lively system.
>
> We still have a way to go for Pharo 7 and onwards. I'm eager to play with the new git based development process and
> interested on how we can manage to build our future Pharo based on the bootstrap efforts.
>
> Even when not finally there ... step by step it goes!
>
> Bye
> T.
>
>
>
> Gesendet: Dienstag, 06. Juni 2017 um 17:11 Uhr
> Von: "Esteban Lorenzano" <estebanlm(a)gmail.com>
> An: "Any question about pharo is welcome" <pharo-users(a)lists.pharo.org>, "Pharo Development List" <pharo-dev(a)lists.pharo.org>, members-consortium(a)pharo.org, "Seaside - general discussion" <seaside(a)lists.squeakfoundation.org>, "list ESUG Mailing" <esug-list(a)lists.esug.org>
> Betreff: [Pharo-dev] [ANN] Pharo 6.0 released!
>
> Dear World,
>
> The time has come for Pharo 6.0!
>
> Pharo is a pure object-oriented programming language and a powerful environment, focused on simplicity and immediate feedback.
>
> This is our most significant release yet. Here are some highlights:
>
>
> - Pharo is now provided in 64-bit version in Linux and OSX and brings even better performance and stability (beware, 64bits version is a new technology and a small amount of tests is still failing)
> - A new code changes management system named Epicea for easier reviewing and recovering of your code easily
> - Integrated support for Git through an easy-to-use tool for repositories and commits management named Iceberg (as a preview for Pharo 6, it will be the default in Pharo 7)
> - The unified foreign function interface (UnifiedFFI) for interfacing with the outside world is significantly improved
> - The PharoVM is now part of OpenSmalltalk initiative
> - Introduction of object immutability, alternative bytecode sets and block closures independent of outer context
> - Pharo can now be bootstrapped from source code managed by Git
> - Pharo modularity is improved
> - Pharo is faster
> - The Dark Theme was improved and set as default color theme of Pharo
>
>
>
> These are just the more prominent highlights, but the details are just as important. We have closed 1474 issues in Pharo 6.0 (a more complete changelog can be found at https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo60Change…)
>
> While the technical improvements are significant (starting the transition to 64bits is a remarkable achievement), still the most impressive fact is that the new code that got in the main Pharo 6.0 image was contributed by more than 80 people.
>
> Pharo is more than code. It is an exciting project involving energetic people. We thank all the contributors of this release:
>
> Alberto Bacchelli, Alejandro Infante, Alexandre Bergel, Aliaksei Syrel, Alistair Grant, Andrei Chis, Ben Coman, Bernardo Contreras, Bernhard Pieber, Boris Spasojevic, Christophe Demarey, Clement Bera, Cyril Ferlicot, Dale Henrichs, Damien Cassou, Damien Pollet, Dave Lewis, Denis Kudriashov, Dirk Roeleveld, Eliot Miranda, Esteban Lorenzano, Esteban Maringolo, Evan Donahue, Federico Balaguer, Franck Warlouzet, Glenn Cavarle, Guillermo Polito, Gustavo Santos, Henrik Johansen, Henrik Nergaard, Hilaire Fernandes, Holger Hans, Jan Kurs, Jan van de Sandt, Johan Fabry, Juraj Kubelka, K. K. Subramaniam, Ken Causey, Kris Gybels, Lionel Akue, Luc Fabresse, Lucas Godoy, Marcus Denker, Mariano Martinez Peck, Marion Noirbent, Martin Dias, Max Leske, Maxime Roelandt, Merwan Ouddane, Matteo Bellotto, Miguel Campusano, Milton Mamani, Myroslava Romaniuk, Nicolai Hess, Nicolas Cellier, Nicolas Passerini, Norbert Hartl, Offray Luna, Pablo Tesone, Paul De Bruicker, Pavel Krivanek, Peter Uhnak, Philippe Back, Roger Stebler, Ronie Salgado, Sean DeNigris, Serge Stinckwich, Skip Lentz, Sophie Kaleba, Stefan Reichhart, Stephan Eggermont, Stephane Ducasse, Sven Van Caekenberghe, Thibault Arloing, Thibault Arloing, Thibault Raffaillac, Thierry Goubier, Thomas Heniart, Tommaso Dal Sasso, Torsten Bergmann, Tudor Girba, Udo Schneider, Valentin Ryckewaert, Vincent Blondeau, Werner Kassens, Yuriy Tymchuk
>
> (If you contributed with Pharo 6.0 development in any way and we missed your name, please send us a mail and we will add you).
>
> Enjoy!
>
> The Pharo Team
>
> Try Pharo: http://pharo.org/download[http://pharo.org/download]
> Learn Pharo: http://pharo.org/documentation[http://pharo.org/documentation]
>
June 6, 2017
[Pharo-dev] [ANN] Pharo 6.0 released!
by Torsten Bergmann
Dear friends,
Yes - really an impressive release. With many cleanups and new treasures in the image - but also many
shiny new/updated external packages and projects (like Roassal, Polymath, Calypso browser, ... to name just a few).
Thanks to all who helped - especially to the ones who cared and also worked on the not so interesting but
often hard to solve issues or boring but necessary parts or infrastructure.
The new git integration in Pharo and the included Iceberg tool will allow us to work with services
like GitHub, GitLab, BitBucket - even own local git servers (for instance setups using Gogs.io). We can now manage
project resources beside code, commit several packages at once and branch and merge as necessary.
This really rocks!
Many thanks also to all the contributors of the OpenSmalltalk initiative - it is also impressive
how much progress was done on VM side. Also thanks to the ones writing new books, articles and tutorials
so other can learn and enjoy such a fantastic dynamic and lively system.
We still have a way to go for Pharo 7 and onwards. I'm eager to play with the new git based development process and
interested on how we can manage to build our future Pharo based on the bootstrap efforts.
Even when not finally there ... step by step it goes!
Bye
T.
Â
Gesendet:Â Dienstag, 06. Juni 2017 um 17:11 Uhr
Von:Â "Esteban Lorenzano" <estebanlm(a)gmail.com>
An:Â "Any question about pharo is welcome" <pharo-users(a)lists.pharo.org>, "Pharo Development List" <pharo-dev(a)lists.pharo.org>, members-consortium(a)pharo.org, "Seaside - general discussion" <seaside(a)lists.squeakfoundation.org>, "list ESUG Mailing" <esug-list(a)lists.esug.org>
Betreff:Â [Pharo-dev] [ANN] Pharo 6.0 released!
Dear World,
Â
The time has come for Pharo 6.0!
Â
Pharo is a pure object-oriented programming language and a powerful environment, focused on simplicity and immediate feedback.
Â
This is our most significant release yet. Here are some highlights:
Â
- Pharo is now provided in 64-bit version in Linux and OSX and brings even better performance and stability (beware, 64bits version is a new technology and a small amount of tests is still failing)
- A new code changes management system named Epicea for easier reviewing and recovering of your code easily
- Integrated support for Git through an easy-to-use tool for repositories and commits management named Iceberg (as a preview for Pharo 6, it will be the default in Pharo 7)
- The unified foreign function interface (UnifiedFFI) for interfacing with the outside world is significantly improved
- The PharoVM is now part of OpenSmalltalk initiative
- Introduction of object immutability, alternative bytecode sets and block closures independent of outer context
- Pharo can now be bootstrapped from source code managed by Git
- Pharo modularity is improved
- Pharo is faster
- The Dark Theme was improved and set as default color theme of Pharo
Â
Â
These are just the more prominent highlights, but the details are just as important. We have closed 1474 issues in Pharo 6.0 (a more complete changelog can be found at https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo60Change…
Â
While the technical improvements are significant (starting the transition to 64bits is a remarkable achievement), still the most impressive fact is that the new code that got in the main Pharo 6.0 image was contributed by more than 80 people.
Â
Pharo is more than code. It is an exciting project involving energetic people. We thank all the contributors of this release:
Â
Alberto Bacchelli, Alejandro Infante, Alexandre Bergel, Aliaksei Syrel, Alistair Grant, Andrei Chis, Ben Coman, Bernardo Contreras, Bernhard Pieber, Boris Spasojevic, Christophe Demarey, Clement Bera, Cyril Ferlicot, Dale Henrichs, Damien Cassou, Damien Pollet, Dave Lewis, Denis Kudriashov, Dirk Roeleveld, Eliot Miranda, Esteban Lorenzano, Esteban Maringolo, Evan Donahue, Federico Balaguer, Franck Warlouzet, Glenn Cavarle, Guillermo Polito, Gustavo Santos, Henrik Johansen, Henrik Nergaard, Hilaire Fernandes, Holger Hans, Jan Kurs, Jan van de Sandt, Johan Fabry, Juraj Kubelka, K. K. Subramaniam, Ken Causey, Kris Gybels, Lionel Akue, Luc Fabresse, Lucas Godoy, Marcus Denker, Mariano Martinez Peck, Marion Noirbent, Martin Dias, Max Leske, Maxime Roelandt, Merwan Ouddane, Matteo Bellotto, Miguel Campusano, Milton Mamani, Myroslava Romaniuk, Nicolai Hess, Nicolas Cellier, Nicolas Passerini, Norbert Hartl, Offray Luna, Pablo Tesone, Paul De Bruicker, Pavel Krivanek, Peter Uhnak, Philippe Back, Roger Stebler, Ronie Salgado, Sean DeNigris, Serge Stinckwich, Skip Lentz, Sophie Kaleba, Stefan Reichhart, Stephan Eggermont, Stephane Ducasse, Sven Van Caekenberghe, Thibault Arloing, Thibault Arloing, Thibault Raffaillac, Thierry Goubier, Thomas Heniart, Tommaso Dal Sasso, Torsten Bergmann, Tudor Girba, Udo Schneider, Valentin Ryckewaert, Vincent Blondeau, Werner Kassens, Yuriy Tymchuk
Â
(If you contributed with Pharo 6.0 development in any way and we missed your name, please send us a mail and we will add you).
Â
Enjoy!
Â
The Pharo Team
Â
Try Pharo: http://pharo.org/download[http://pharo.org/download]
Learn Pharo: http://pharo.org/documentation[http://pharo.org/documentation]
June 6, 2017
Re: [Pharo-users] [ANN] Pharo 6.0 released!
by Hilaire
Congratulations !
Le 06/06/2017 à 17:11, Esteban Lorenzano a écrit :
> The time has come for Pharo 6.0!
>
--
Dr. Geo
http://drgeo.eu
June 6, 2017
is it related to Freetype or Athens?
by Hilaire
Hi there,
A Dr. Geo user on Ubuntu 64bits 16.04 got that buggy rendering of the
canvas, then on some situation the rendering completely stop on a red
screen, with a stack showing may be a zero divide error. I did not get
access to the PharoDebog yet.
Fonts on the screenshot is not right too. Could it be a mixed problem
between FreeType and Cairo? Any first though on the issue welcome.
Given the fact Dr. Geo is still based on Pharo3 and it works pretty fine
on my old Ubuntu 12.07 derived system, it may be time to port the newer
Pharo6.
Congrats for the Pharo6 release.
Hilaire
--
Dr. Geo
http://drgeo.eu
June 6, 2017
Re: [Pharo-users] [Pharo-dev] [ANN] Pharo 6.0 released!
by Raffaello Giulietti
> On Tue, Jun 6, 2017 at 11:11 PM, Esteban Lorenzano <estebanlm(a)gmail.com> wrote:
> Dear World,
>
> The time has come for Pharo 6.0!
>
Nice!
Thanks to all contributors.
Greetings
Raffaello
June 6, 2017
Re: [Pharo-users] [Pharo-dev] [ANN] Pharo 6.0 released!
by Sven Van Caekenberghe
> On 6 Jun 2017, at 18:18, Ben Coman <btc(a)openinworld.com> wrote:
>
>
>
> On Tue, Jun 6, 2017 at 11:11 PM, Esteban Lorenzano <estebanlm(a)gmail.com> wrote:
> Dear World,
>
> The time has come for Pharo 6.0!
>
> Woot!
> cheers -ben
Super. Thank you all.
June 6, 2017
Re: [Pharo-users] [ANN] Pharo 6.0 released!
by Ben Coman
On Tue, Jun 6, 2017 at 11:11 PM, Esteban Lorenzano <estebanlm(a)gmail.com>
wrote:
> Dear World,
>
> The time has come for Pharo 6.0!
>
Woot!
cheers -ben
June 6, 2017
Re: [Pharo-users] [ANN] Pharo 6.0 released!
by Norbert Hartl
It is really great! Thank you all! I'm glad the struggles with 32 bit libraries will have an end for normal deployments. The same goes for uFFI that makes things so much easier. And of course the rest of the list of changes is impressive as always.
Glad to be part of this community. You rock!
Norbert
> Am 06.06.2017 um 17:11 schrieb Esteban Lorenzano <estebanlm(a)gmail.com>:
>
> Dear World,
>
> The time has come for Pharo 6.0!
>
> Pharo is a pure object-oriented programming language and a powerful environment, focused on simplicity and immediate feedback.
>
> This is our most significant release yet. Here are some highlights:
>
> - Pharo is now provided in 64-bit version in Linux and OSX and brings even better performance and stability (beware, 64bits version is a new technology and a small amount of tests is still failing)
> - A new code changes management system named Epicea for easier reviewing and recovering of your code easily
> - Integrated support for Git through an easy-to-use tool for repositories and commits management named Iceberg (as a preview for Pharo 6, it will be the default in Pharo 7)
> - The unified foreign function interface (UnifiedFFI) for interfacing with the outside world is significantly improved
> - The PharoVM is now part of OpenSmalltalk initiative
> - Introduction of object immutability, alternative bytecode sets and block closures independent of outer context
> - Pharo can now be bootstrapped from source code managed by Git
> - Pharo modularity is improved
> - Pharo is faster
> - The Dark Theme was improved and set as default color theme of Pharo
>
> <Pharo6.jpeg>
>
> These are just the more prominent highlights, but the details are just as important. We have closed 1474 issues in Pharo 6.0 (a more complete changelog can be found at https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo60Change… <https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo60Change…>).
>
> While the technical improvements are significant (starting the transition to 64bits is a remarkable achievement), still the most impressive fact is that the new code that got in the main Pharo 6.0 image was contributed by more than 80 people.
>
> Pharo is more than code. It is an exciting project involving energetic people. We thank all the contributors of this release:
>
> Alberto Bacchelli, Alejandro Infante, Alexandre Bergel, Aliaksei Syrel, Alistair Grant, Andrei Chis, Ben Coman, Bernardo Contreras, Bernhard Pieber, Boris Spasojevic, Christophe Demarey, Clement Bera, Cyril Ferlicot, Dale Henrichs, Damien Cassou, Damien Pollet, Dave Lewis, Denis Kudriashov, Dirk Roeleveld, Eliot Miranda, Esteban Lorenzano, Esteban Maringolo, Evan Donahue, Federico Balaguer, Franck Warlouzet, Glenn Cavarle, Guillermo Polito, Gustavo Santos, Henrik Johansen, Henrik Nergaard, Hilaire Fernandes, Holger Hans, Jan Kurs, Jan van de Sandt, Johan Fabry, Juraj Kubelka, K. K. Subramaniam, Ken Causey, Kris Gybels, Lionel Akue, Luc Fabresse, Lucas Godoy, Marcus Denker, Mariano Martinez Peck, Marion Noirbent, Martin Dias, Max Leske, Maxime Roelandt, Merwan Ouddane, Matteo Bellotto, Miguel Campusano, Milton Mamani, Myroslava Romaniuk, Nicolai Hess, Nicolas Cellier, Nicolas Passerini, Norbert Hartl, Offray Luna, Pablo Tesone, Paul De Bruicker, Pavel Krivanek, Peter Uhnak, Philippe Back, Roger Stebler, Ronie Salgado, Sean DeNigris, Serge Stinckwich, Skip Lentz, Sophie Kaleba, Stefan Reichhart, Stephan Eggermont, Stephane Ducasse, Sven Van Caekenberghe, Thibault Arloing, Thibault Arloing, Thibault Raffaillac, Thierry Goubier, Thomas Heniart, Tommaso Dal Sasso, Torsten Bergmann, Tudor Girba, Udo Schneider, Valentin Ryckewaert, Vincent Blondeau, Werner Kassens, Yuriy Tymchuk
>
> (If you contributed with Pharo 6.0 development in any way and we missed your name, please send us a mail and we will add you).
>
> Enjoy!
>
> The Pharo Team
>
> Try Pharo: http://pharo.org/download <http://pharo.org/download>
> Learn Pharo: http://pharo.org/documentation <http://pharo.org/documentation>
June 6, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Ben Coman
On Tue, Jun 6, 2017 at 9:11 PM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
wrote:
> Thanks for the detailed answer ben :)
>
> I will try to clarify a little: the question is how to loosely wire
> objects, such as MovieLister to MovieFinder, so that changes in the wiring
> can be made without effort. In Java, people use DI containers and xml files
> or annotations to provide the wiring configuration, which is easy to switch
> entirely. For example, I could have a xml file for production code and
> another for testing purposes.
>
> Also, another advantage is that the container takes care of ordering
> object creation for me. For example, if the object A, B and C needed to be
> injected on the object Y, I just have to declare each one of those objects
> on the configuration file, the container arranges the creation order for
> me.
>
I don't see what is special about this. You can easily arrange instance
creation order with methods on the class-side of your domain classes.
Indeed, the GTTools are set up to work with in-Image sample data. Look at
implementors of #sample and #example.
There was quite some bike-shedding over the naming convention (and I forget
the final result), but hopefully it provide the general idea...
http://forum.world.st/a-request-to-change-the-meaning-of-lt-example-gt-prag…
http://forum.world.st/lt-example-gt-lt-examplar-gt-td4911728i20.html
http://forum.world.st/Existing-lt-script-gt-lt-example-gt-pragmas-and-new-G…
>
> I started, however, to question DI as a valid mechanisms because of it's
> complexities and other problems. The article from Fowler provides the
> service locator as an alternative which seems to me much simpler and
> completely fine solution for the problem.
>
If it seems suitable, then to quote Nike, just do it ;)
> So, to answer you question "Is it any more complicated than that?": In
> the DI approach, yes it can be, but I don't think so in the service locator
> approach.
>
> I am asking here because I wanted to know how people from Smalltalk deal
> with this problem. As it seems there is no standard approach, nor this is
> perceived as a problem...
>
DI or Service Locator are both "implementations" of your need. Can we take
step backward to see what is your need? To kick off, I hazard a guess at
some possible needs...
1. To switch between configurations to use production data and test data ?
2. To make this switch during CI testing and production deployment ?
3. To switch from the command line ?
4. Want the configuration to editable remotely? e.g. from a text editor?
?
...
> You think it is enough to do the wiring by hand?
>
I'm having trouble understanding this "by hand" concept.
Don't you create the xml configuration file by hand?
You can just as easily
> It is ok to use a service locator approach? Or wouldn't you care about
> that?
>
If it works, its okay.
So very generally, I'd avoid starting with any external test data, so as to
not distract myself by that implementation.
I'd copy-paste some test data into the class-side-methods of the domain
classes and hack some instance creation code around them.
Build your first tests around those. Then later, consolidate them via an
InImageTestData object that you'll later replace with ExternalTestData
>
>
> but I'll add, it was so much simpler to understand without all that Java
>> typing boiler plate.
>
>
> Yeah, that's for sure! I am just used to read Java code.
>
> []s,
> Vitor
>
>
>
As an aside, try evaluting "Smalltalk tools inspect"
and debugging "Smalltalk tools browser open"
cheers -ben
June 6, 2017
Re: [Pharo-users] [ANN] Pharo 6.0 released!
by Offray Vladimir Luna Cárdenas
Thanks community and specially Esteban!
Happy of this release and put my two pesos into this!
Congrats,
Offray
On 06/06/17 10:11, Esteban Lorenzano wrote:
> Dear World,
>
> The time has come for Pharo 6.0!
>
> Pharo is a pure object-oriented programming language and a powerful
> environment, focused on simplicity and immediate feedback.
>
> This is our most significant release yet. Here are some highlights:
>
> - Pharo is now provided in 64-bit version in Linux and OSX and brings
> even better performance and stability (beware, 64bits version is a new
> technology and a small amount of tests is still failing)
> - A new code changes management system named Epicea for easier
> reviewing and recovering of your code easily
> - Integrated support for Git through an easy-to-use tool for
> repositories and commits management named Iceberg (as a preview for
> Pharo 6, it will be the default in Pharo 7)
> - The unified foreign function interface (UnifiedFFI) for interfacing
> with the outside world is significantly improved
> - The PharoVM is now part of OpenSmalltalk initiative
> - Introduction of object immutability, alternative bytecode sets and
> block closures independent of outer context
> - Pharo can now be bootstrapped from source code managed by Git
> - Pharo modularity is improved
> - Pharo is faster
> - The Dark Theme was improved and set as default color theme of Pharo
>
>
> These are just the more prominent highlights, but the details are just
> as important. We have closed 1474 issues in Pharo 6.0 (a more complete
> changelog can be found at
> https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo60Change…)
>
> While the technical improvements are significant (starting the
> transition to 64bits is a remarkable achievement), still the most
> impressive fact is that the new code that got in the main Pharo 6.0
> image was contributed by more than 80 people.
>
> Pharo is more than code. It is an exciting project involving energetic
> people. We thank all the contributors of this release:
>
> Alberto Bacchelli, Alejandro Infante, Alexandre Bergel, Aliaksei
> Syrel, Alistair Grant, Andrei Chis, Ben Coman, Bernardo Contreras,
> Bernhard Pieber, Boris Spasojevic, Christophe Demarey, Clement Bera,
> Cyril Ferlicot, Dale Henrichs, Damien Cassou, Damien Pollet, Dave
> Lewis, Denis Kudriashov, Dirk Roeleveld, Eliot Miranda, Esteban
> Lorenzano, Esteban Maringolo, Evan Donahue, Federico Balaguer, Franck
> Warlouzet, Glenn Cavarle, Guillermo Polito, Gustavo Santos, Henrik
> Johansen, Henrik Nergaard, Hilaire Fernandes, Holger Hans, Jan Kurs,
> Jan van de Sandt, Johan Fabry, Juraj Kubelka, K. K. Subramaniam, Ken
> Causey, Kris Gybels, Lionel Akue, Luc Fabresse, Lucas Godoy, Marcus
> Denker, Mariano Martinez Peck, Marion Noirbent, Martin Dias, Max
> Leske, Maxime Roelandt, Merwan Ouddane, Matteo Bellotto, Miguel
> Campusano, Milton Mamani, Myroslava Romaniuk, Nicolai Hess, Nicolas
> Cellier, Nicolas Passerini, Norbert Hartl, Offray Luna, Pablo Tesone,
> Paul De Bruicker, Pavel Krivanek, Peter Uhnak, Philippe Back, Roger
> Stebler, Ronie Salgado, Sean DeNigris, Serge Stinckwich, Skip Lentz,
> Sophie Kaleba, Stefan Reichhart, Stephan Eggermont, Stephane Ducasse,
> Sven Van Caekenberghe, Thibault Arloing, Thibault Arloing, Thibault
> Raffaillac, Thierry Goubier, Thomas Heniart, Tommaso Dal Sasso,
> Torsten Bergmann, Tudor Girba, Udo Schneider, Valentin Ryckewaert,
> Vincent Blondeau, Werner Kassens, Yuriy Tymchuk
>
> (If you contributed with Pharo 6.0 development in any way and we
> missed your name, please send us a mail and we will add you).
>
> Enjoy!
>
> The Pharo Team
>
> Try Pharo: http://pharo.org/download
> Learn Pharo: http://pharo.org/documentation
June 6, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Attila Magyar
I don't think using a DI container worth the effort. They add lots of
complexities and solve very little. For some reason DI containers became
very popular in the Java world, but if you take a look at other programming
communities you'll realize that many people are perfectly happy without
using these containers. Using DI and using a DI container is orthogonal. As
you also said you can just pass dependencies to objects to achieve loose
coupling. Yes, you have to do this manually but what's the big deal? We're
talking about code with cyclomatic complexity of 1. Calling a constructor is
not a problem that need to be solved. Using an external XML configuration to
describe object wiring is the worst idea ever.
Here is an article about using plain old object composition to do DI
http://blog.davidpeterson.co.uk/2011/01/object-oriented-example.html
Some more thoughts about the problems associated with DI containers:
http://www.natpryce.com/articles/000783.html
http://higherorderlogic.com/2011/07/is-dependency-injection-like-facebook
--
View this message in context: http://forum.world.st/Wiring-objects-IoC-and-Service-Locator-tp4949280p4949…
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 6, 2017
Re: [Pharo-users] [ANN] Pharo 6.0 released!
by Tudor Girba
Great work!
Doru
> On Jun 6, 2017, at 5:11 PM, Esteban Lorenzano <estebanlm(a)gmail.com> wrote:
>
> Dear World,
>
> The time has come for Pharo 6.0!
>
> Pharo is a pure object-oriented programming language and a powerful environment, focused on simplicity and immediate feedback.
>
> This is our most significant release yet. Here are some highlights:
>
> - Pharo is now provided in 64-bit version in Linux and OSX and brings even better performance and stability (beware, 64bits version is a new technology and a small amount of tests is still failing)
> - A new code changes management system named Epicea for easier reviewing and recovering of your code easily
> - Integrated support for Git through an easy-to-use tool for repositories and commits management named Iceberg (as a preview for Pharo 6, it will be the default in Pharo 7)
> - The unified foreign function interface (UnifiedFFI) for interfacing with the outside world is significantly improved
> - The PharoVM is now part of OpenSmalltalk initiative
> - Introduction of object immutability, alternative bytecode sets and block closures independent of outer context
> - Pharo can now be bootstrapped from source code managed by Git
> - Pharo modularity is improved
> - Pharo is faster
> - The Dark Theme was improved and set as default color theme of Pharo
>
> <Pharo6.jpeg>
>
> These are just the more prominent highlights, but the details are just as important. We have closed 1474 issues in Pharo 6.0 (a more complete changelog can be found at https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo60Change…)
>
> While the technical improvements are significant (starting the transition to 64bits is a remarkable achievement), still the most impressive fact is that the new code that got in the main Pharo 6.0 image was contributed by more than 80 people.
>
> Pharo is more than code. It is an exciting project involving energetic people. We thank all the contributors of this release:
>
> Alberto Bacchelli, Alejandro Infante, Alexandre Bergel, Aliaksei Syrel, Alistair Grant, Andrei Chis, Ben Coman, Bernardo Contreras, Bernhard Pieber, Boris Spasojevic, Christophe Demarey, Clement Bera, Cyril Ferlicot, Dale Henrichs, Damien Cassou, Damien Pollet, Dave Lewis, Denis Kudriashov, Dirk Roeleveld, Eliot Miranda, Esteban Lorenzano, Esteban Maringolo, Evan Donahue, Federico Balaguer, Franck Warlouzet, Glenn Cavarle, Guillermo Polito, Gustavo Santos, Henrik Johansen, Henrik Nergaard, Hilaire Fernandes, Holger Hans, Jan Kurs, Jan van de Sandt, Johan Fabry, Juraj Kubelka, K. K. Subramaniam, Ken Causey, Kris Gybels, Lionel Akue, Luc Fabresse, Lucas Godoy, Marcus Denker, Mariano Martinez Peck, Marion Noirbent, Martin Dias, Max Leske, Maxime Roelandt, Merwan Ouddane, Matteo Bellotto, Miguel Campusano, Milton Mamani, Myroslava Romaniuk, Nicolai Hess, Nicolas Cellier, Nicolas Passerini, Norbert Hartl, Offray Luna, Pablo Tesone, Paul De Bruicker, Pavel Krivanek, Peter Uhnak, Philippe Back, Roger Stebler, Ronie Salgado, Sean DeNigris, Serge Stinckwich, Skip Lentz, Sophie Kaleba, Stefan Reichhart, Stephan Eggermont, Stephane Ducasse, Sven Van Caekenberghe, Thibault Arloing, Thibault Arloing, Thibault Raffaillac, Thierry Goubier, Thomas Heniart, Tommaso Dal Sasso, Torsten Bergmann, Tudor Girba, Udo Schneider, Valentin Ryckewaert, Vincent Blondeau, Werner Kassens, Yuriy Tymchuk
>
> (If you contributed with Pharo 6.0 development in any way and we missed your name, please send us a mail and we will add you).
>
> Enjoy!
>
> The Pharo Team
>
> Try Pharo: http://pharo.org/download
> Learn Pharo: http://pharo.org/documentation
--
www.tudorgirba.com
www.feenk.com
âSoftware has no shape. Actually, it has no one shape. It has many."
June 6, 2017
Re: [Pharo-users] [Pharo-dev] [ANN] Pharo 6.0 released!
by volkert
Thank you Estaban for all your hard work.
Volkert
Am 06.06.2017 um 17:11 schrieb Esteban Lorenzano:
> Dear World,
>
> The time has come for Pharo 6.0!
>
> Pharo is a pure object-oriented programming language and a powerful
> environment, focused on simplicity and immediate feedback.
>
> This is our most significant release yet. Here are some highlights:
>
> - Pharo is now provided in 64-bit version in Linux and OSX and brings
> even better performance and stability (beware, 64bits version is a new
> technology and a small amount of tests is still failing)
> - A new code changes management system named Epicea for easier
> reviewing and recovering of your code easily
> - Integrated support for Git through an easy-to-use tool for
> repositories and commits management named Iceberg (as a preview for
> Pharo 6, it will be the default in Pharo 7)
> - The unified foreign function interface (UnifiedFFI) for interfacing
> with the outside world is significantly improved
> - The PharoVM is now part of OpenSmalltalk initiative
> - Introduction of object immutability, alternative bytecode sets and
> block closures independent of outer context
> - Pharo can now be bootstrapped from source code managed by Git
> - Pharo modularity is improved
> - Pharo is faster
> - The Dark Theme was improved and set as default color theme of Pharo
>
>
> These are just the more prominent highlights, but the details are just
> as important. We have closed 1474 issues in Pharo 6.0 (a more complete
> changelog can be found at
> https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo60Change…)
>
>
> While the technical improvements are significant (starting the
> transition to 64bits is a remarkable achievement), still the most
> impressive fact is that the new code that got in the main Pharo 6.0
> image was contributed by more than 80 people.
>
> Pharo is more than code. It is an exciting project involving energetic
> people. We thank all the contributors of this release:
>
> Alberto Bacchelli, Alejandro Infante, Alexandre Bergel, Aliaksei
> Syrel, Alistair Grant, Andrei Chis, Ben Coman, Bernardo Contreras,
> Bernhard Pieber, Boris Spasojevic, Christophe Demarey, Clement Bera,
> Cyril Ferlicot, Dale Henrichs, Damien Cassou, Damien Pollet, Dave
> Lewis, Denis Kudriashov, Dirk Roeleveld, Eliot Miranda, Esteban
> Lorenzano, Esteban Maringolo, Evan Donahue, Federico Balaguer, Franck
> Warlouzet, Glenn Cavarle, Guillermo Polito, Gustavo Santos, Henrik
> Johansen, Henrik Nergaard, Hilaire Fernandes, Holger Hans, Jan Kurs,
> Jan van de Sandt, Johan Fabry, Juraj Kubelka, K. K. Subramaniam, Ken
> Causey, Kris Gybels, Lionel Akue, Luc Fabresse, Lucas Godoy, Marcus
> Denker, Mariano Martinez Peck, Marion Noirbent, Martin Dias, Max
> Leske, Maxime Roelandt, Merwan Ouddane, Matteo Bellotto, Miguel
> Campusano, Milton Mamani, Myroslava Romaniuk, Nicolai Hess, Nicolas
> Cellier, Nicolas Passerini, Norbert Hartl, Offray Luna, Pablo Tesone,
> Paul De Bruicker, Pavel Krivanek, Peter Uhnak, Philippe Back, Roger
> Stebler, Ronie Salgado, Sean DeNigris, Serge Stinckwich, Skip Lentz,
> Sophie Kaleba, Stefan Reichhart, Stephan Eggermont, Stephane Ducasse,
> Sven Van Caekenberghe, Thibault Arloing, Thibault Arloing, Thibault
> Raffaillac, Thierry Goubier, Thomas Heniart, Tommaso Dal Sasso,
> Torsten Bergmann, Tudor Girba, Udo Schneider, Valentin Ryckewaert,
> Vincent Blondeau, Werner Kassens, Yuriy Tymchuk
>
> (If you contributed with Pharo 6.0 development in any way and we
> missed your name, please send us a mail and we will add you).
>
> Enjoy!
>
> The Pharo Team
>
> Try Pharo: http://pharo.org/download
> Learn Pharo: http://pharo.org/documentation
June 6, 2017
[ANN] Pharo 6.0 released!
by Esteban Lorenzano
Dear World,
The time has come for Pharo 6.0!
Pharo is a pure object-oriented programming language and a powerful environment, focused on simplicity and immediate feedback.
This is our most significant release yet. Here are some highlights:
- Pharo is now provided in 64-bit version in Linux and OSX and brings even better performance and stability (beware, 64bits version is a new technology and a small amount of tests is still failing)
- A new code changes management system named Epicea for easier reviewing and recovering of your code easily
- Integrated support for Git through an easy-to-use tool for repositories and commits management named Iceberg (as a preview for Pharo 6, it will be the default in Pharo 7)
- The unified foreign function interface (UnifiedFFI) for interfacing with the outside world is significantly improved
- The PharoVM is now part of OpenSmalltalk initiative
- Introduction of object immutability, alternative bytecode sets and block closures independent of outer context
- Pharo can now be bootstrapped from source code managed by Git
- Pharo modularity is improved
- Pharo is faster
- The Dark Theme was improved and set as default color theme of Pharo
These are just the more prominent highlights, but the details are just as important. We have closed 1474 issues in Pharo 6.0 (a more complete changelog can be found at https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo60Change…)
While the technical improvements are significant (starting the transition to 64bits is a remarkable achievement), still the most impressive fact is that the new code that got in the main Pharo 6.0 image was contributed by more than 80 people.
Pharo is more than code. It is an exciting project involving energetic people. We thank all the contributors of this release:
Alberto Bacchelli, Alejandro Infante, Alexandre Bergel, Aliaksei Syrel, Alistair Grant, Andrei Chis, Ben Coman, Bernardo Contreras, Bernhard Pieber, Boris Spasojevic, Christophe Demarey, Clement Bera, Cyril Ferlicot, Dale Henrichs, Damien Cassou, Damien Pollet, Dave Lewis, Denis Kudriashov, Dirk Roeleveld, Eliot Miranda, Esteban Lorenzano, Esteban Maringolo, Evan Donahue, Federico Balaguer, Franck Warlouzet, Glenn Cavarle, Guillermo Polito, Gustavo Santos, Henrik Johansen, Henrik Nergaard, Hilaire Fernandes, Holger Hans, Jan Kurs, Jan van de Sandt, Johan Fabry, Juraj Kubelka, K. K. Subramaniam, Ken Causey, Kris Gybels, Lionel Akue, Luc Fabresse, Lucas Godoy, Marcus Denker, Mariano Martinez Peck, Marion Noirbent, Martin Dias, Max Leske, Maxime Roelandt, Merwan Ouddane, Matteo Bellotto, Miguel Campusano, Milton Mamani, Myroslava Romaniuk, Nicolai Hess, Nicolas Cellier, Nicolas Passerini, Norbert Hartl, Offray Luna, Pablo Tesone, Paul De Bruicker, Pavel Krivanek, Peter Uhnak, Philippe Back, Roger Stebler, Ronie Salgado, Sean DeNigris, Serge Stinckwich, Skip Lentz, Sophie Kaleba, Stefan Reichhart, Stephan Eggermont, Stephane Ducasse, Sven Van Caekenberghe, Thibault Arloing, Thibault Arloing, Thibault Raffaillac, Thierry Goubier, Thomas Heniart, Tommaso Dal Sasso, Torsten Bergmann, Tudor Girba, Udo Schneider, Valentin Ryckewaert, Vincent Blondeau, Werner Kassens, Yuriy Tymchuk
(If you contributed with Pharo 6.0 development in any way and we missed your name, please send us a mail and we will add you).
Enjoy!
The Pharo Team
Try Pharo: http://pharo.org/download
Learn Pharo: http://pharo.org/documentation
June 6, 2017
Re: [Pharo-users] Bloc/Brick/Spec
by Ben Coman
On Tue, Jun 6, 2017 at 9:20 AM, Brad Selfridge <bsselfridge(a)gmail.com>
wrote:
> I'm confused. I see the latest news and documentation about Bloc. Is Brick
> now dead and Bloc the default? I thought Brick was a layer on top of Bloc
> and Spec was layer on top on Brick? What is the direction now?
>
> Brad Selfridge
>
>
Can you link to this latest news?
cheers -ben
June 6, 2017
Re: [Pharo-users] How to use uFFI with String
by Pierce Ng
On Sat, May 27, 2017 at 06:15:47AM -0700, horrido wrote:
> Yes, I did. I found it difficult to understand. It would be nice to have some
> clear examples in the documentation, for example, really simple and common
> situations such as a C function returning an integer in a
> passed-by-reference argument.
I've written such a thing:
https://github.com/PierceNg/libffidemo
See these functions in the C library:
int get_by_filling_pointer(demo_thing *pthing, int *pvalue)
int get_by_returned_value(demo_thing *pthing)
Two follow-up blog posts:
http://www.samadhiweb.com/blog/2016.03.12.demoffi.html
http://www.samadhiweb.com/blog/2016.03.17.demoffi.html
I intend to modify my blog posts to contribute to the booklet, sometime in this
month of June.
Pierce
June 6, 2017
Re: [Pharo-users] Morphic or forking bug?
by Sven Van Caekenberghe
You are mixing 3 different aspects:
- how to update a UI from a background process
- how to maintain a background process over image save/open
- how to communicate between the 2
Safe UI updating has to happen using #step or #defer: and should be quick/short as not to block the UI.
Although processes survive over image save/open (provided they did not become garbage), this is dangerous as they come up immediately (too soon) and will probably hold external resources (files/sockets/..) that will have changed (and result in a crash). It is better to manage this explicitly using #startUp and #shutDown.
Communication between the 2 should be protected using a semaphore.
Here is an example of a 'file watcher', a little window that shows the first line of a specific file, updating it every 3 seconds (silly and too resource intensive, it is just a demo). You can edit the file manually to modify the contents of the first line and see it being picked up in Pharo (within 3 seconds).
Here is the code as 1 file/class in '_UnpackagedPackage':
See the class side #initialize for the #startUp and #shutDown registration, sent to all instances as #start and #stop (a bit rude but good enough for the demo).
Instance side #initialize sets up the mutex that gets used in the #firstLine and #firstLine: accessors.
The actual process is in #run which calls #updateFirstLine
The UI updating is in #step which calls #updateFileLineDisplay
Subscribing to MorphDeleted via the announcer allows for the process to stop when the window closes.
The file watcher window and process survive an image save/open (i.e. they keep on working).
HTH,
Sven
> On 3 Jun 2017, at 15:44, horrido <horrido.hobbies(a)gmail.com> wrote:
>
> Okay, let me explain my application...
>
> It displays a Morphic window containing lines of information that are
> updateable in real time on a periodic basis. As I indicated in the original
> post, the code skeleton is basically:
>
> initA
> a := ((StringMorph contents: '####') color: Color white) position: (0@0).
> m addMorph: a
>
> initialize
> f := Form fromFileNamed: 'hot_air_balloon_mysticmorning.jpg'.
> m := ImageMorph new.
> m form: f.
> self initA.
> m openInWindowLabeled: 'Cranky'.
> delay := (Delay forSeconds: 5).
> [ [ true ] whileTrue: [ a contents: 0 asString. delay wait ] fork
>
> Imagine that #initA creates many such StringMorphs, each displaying a
> different kind of information.
>
> In the endless loop, imagine that instead of 'a contents: 0 asString', I'm
> updating all of the StringMorphs I created in #initA.
>
> The need to do this in a separate thread is to prevent Pharo from being
> completely frozen during the 'delay wait', which is practically all the
> time!
>
> Now, I did try Hilaire's suggestion to use Morphic's step protocol instead.
> But in my test scenario of closing the app/saving and exiting the
> image/restarting the image, repeatedly (in may take 10-20 times), it still
> causes the occasional segmentation fault.
>
> So if the problem is updating a structure in the main thread from another
> process, then why did Hilaire's suggestion not solve the problem?
>
> It seems to me, then, either way, it's an issue of multithreading...whether
> my way or Hilaire's way.
>
>
>
> Sven Van Caekenberghe-2 wrote
>> Hi Horrido,
>>
>> It is very hard to follow what you are exactly doing or trying to do.
>>
>> Here is the simplest example I can think of that updates something in
>> Morphic on a regular basis.
>>
>> StringMorph subclass: #MyClock
>> instanceVariableNames: ''
>> classVariableNames: ''
>> package: '_UnpackagedPackage'
>>
>> MyClock>>#initialize
>> super initialize.
>> self updateClock
>>
>> MyClock>>#step
>> self updateClock
>>
>> MyClock>>#updateClock
>> self contents: Time now printString
>>
>> MyClock class>>#open
>> "self open"
>>
>> ^ self new openInWindow
>>
>> This inherits #stepTime as 1 second. If I open such a window and save my
>> image, it is still there when the image is restarted, with the clock still
>> working.
>>
>> Updating (data structures in) the main UI process from another process is
>> dangerous. Saving such constructs is even more dangerous.
>>
>> HTH,
>>
>> Sven
>>
>>> On 2 Jun 2017, at 15:54, horrido <
>
>> horrido.hobbies@
>
>> > wrote:
>>>
>>> Sorry, I could be mistaken. I just checked my notes. The *0 asString*
>>> test
>>> failed once, but I've not been able to replicate it. I might've been
>>> working
>>> with an unclean image.
>>>
>>> So perhaps it is related to Morphic, after all.
>>>
>>>
>>> horrido wrote
>>>> Yup, they all fail. Interesting that
>>> *
>>>> 0 asString
>>> *
>>>> fails. This means it has NOTHING to do with Morphic (or Morphic being
>>>> thread-unsafe).
>>>>
>>>> Ben Coman wrote
>>>>> On Wed, May 31, 2017 at 10:23 PM, horrido <
>>>
>>>>> horrido.hobbies@
>>>
>>>>> > wrote:
>>>>>
>>>>> Can you try a few other variations...
>>>>> [ [ true ] whileTrue: [ 0 asString. delay wait ] fork.
>>>>> [ [ true ] whileTrue: [ a contents: '0'. delay wait ] fork.
>>>>> [ [ true ] whileTrue: [ a contents: '0'. ] forkAt: 20.
>>>>>
>>>>> cheers -ben
>>>
>>>
>>>
>>>
>>>
>>> --
>>> View this message in context:
>>> http://forum.world.st/Morphic-or-forking-bug-tp4948727p4948984.html
>>> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>
>
>
>
>
> --
> View this message in context: http://forum.world.st/Morphic-or-forking-bug-tp4948727p4949166.html
> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 6, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Vitor Medina Cruz
Thanks for the detailed answer ben :)
I will try to clarify a little: the question is how to loosely wire
objects, such as MovieLister to MovieFinder, so that changes in the wiring
can be made without effort. In Java, people use DI containers and xml files
or annotations to provide the wiring configuration, which is easy to switch
entirely. For example, I could have a xml file for production code and
another for testing purposes.
Also, another advantage is that the container takes care of ordering object
creation for me. For example, if the object A, B and C needed to be
injected on the object Y, I just have to declare each one of those objects
on the configuration file, the container arranges the creation order for
me.
I started, however, to question DI as a valid mechanisms because of it's
complexities and other problems. The article from Fowler provides the
service locator as an alternative which seems to me much simpler and
completely fine solution for the problem.
So, to answer you question "Is it any more complicated than that?": In the
DI approach, yes it can be, but I don't think so in the service locator
approach.
I am asking here because I wanted to know how people from Smalltalk deal
with this problem. As it seems there is no standard approach, nor this is
perceived as a problem... You think it is enough to do the wiring by hand?
It is ok to use a service locator approach? Or wouldn't you care about that?
but I'll add, it was so much simpler to understand without all that Java
> typing boiler plate.
Yeah, that's for sure! I am just used to read Java code.
[]s,
Vitor
On Mon, Jun 5, 2017 at 9:46 PM, Ben Coman <btc(a)openinworld.com> wrote:
>
>
> On Tue, Jun 6, 2017 at 5:11 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
> wrote:
>
>> Tx ben.
>> When I see all this complexity for something that looks not that complex:
>> I prefer to pass the class and get done.
>> May be I missed something obvious... but when I see something too complex
>> I start to get worried.
>>
>> I think that thinking about the contract between classes at runtime is
>> important and to me a MovieLister should be using at runtime and instance
>> of the *Finder*
>> Now needing an extra class just to set this should really be evaluated
>> with the tradeoff: "flexibility win" (our simple solution is still really
>> flexible - I decide when I want to pass the correct finder) vs. the code
>> and conceptual bloat.
>>
>>
>> I'm happy not to face the hyper super over engineering of Java
>> "solutions".
>>
>> I like the "Of course this just shifts the burden a tad, we still have
>> to get the locator into the lister"
>> but the solution is super simple let us use another "Singleton and a
>> Factory...." :)
>>
>> Stef
>>
>> On Mon, Jun 5, 2017 at 8:43 PM, Ben Coman <btc(a)openinworld.com> wrote:
>>
>>>
>>>
>>> On Tue, Jun 6, 2017 at 1:26 AM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
>>> wrote:
>>>
>>>> Thanks for the answer Ben and Stephane.
>>>>
>>>> I already read A Mentoring Course on Smalltalk, Valloud, there is
>>>> nothing there I could use in this case :( . I will look after for The
>>>> Design Patterns Smalltalk Companion. Most of the sources provided I already
>>>> know of or went in the same lines lines of what I have already found.
>>>>
>>>> About TDD, I am experienced with the discipline and have tested it on
>>>> Pharo living system already, but I could not understand how this is related
>>>> with object wiring, DI and service locator.
>>>>
>>>
>>> I guess I don't properly understand your need and those topics. That
>>> was my quick pass. Now if I take the time to actually read Fowler's long
>>> article
>>>
>>> "the inversion is about how they lookup a plugin implementation ... to
>>> ensure that any user of a plugin follows some convention that allows a
>>> separate assembler module to inject the implementation into the lister."
>>>
>>> "The basic idea of the Dependency Injection is to have a separate
>>> object, an assembler, that populates a field in the lister class with an
>>> appropriate implementation for the finder interface. There are three main
>>> styles of dependency injection. The names I'm using for them are
>>> Constructor Injection, Setter Injection, and Interface Injection."
>>>
>>> Now there was too much syntactical noise in those Java examples for me
>>> to think clearly, so I converted them all to Smalltalk.
>>>
>>>
>>> ##CONSTRUCTOR INJECTION
>>>
>>> Object subclass: MovieLister
>>> instanceVariables: 'finder'
>>>
>>>
>>> MovieLister class >> newWith: aFinder
>>> ^ self basicNew initializeWith: aFinder
>>>
>>> MovieLister >> initializeWith: aFinder
>>> finder := aFinder
>>>
>>>
>>> ColonMovieFinder class >> newWith: aFilename
>>> ^ self basicNew initializeWith: aFilename
>>>
>>> ColonMovieFinder >> initializeWith: aFilename
>>> filename := aFilename.
>>>
>>>
>>> ConstructorInjectionContainer >> new
>>> container := DefaultContainer new. "the article doesn't specify
>>> where this comes from"
>>> finderParams := ConstantParameter newWith: 'movies1.txt'.
>>> container registerComponentInterface: MovieFinderInterface
>>> implementation: ColonMovieFinder
>>> params: finderParams.
>>> container registerComponentImplementation: MovieLister
>>> ^container
>>>
>>> to be used like this...
>>> ConstructorInjectionTest >> testWithContainer
>>> container := ConstructorInjectionContainer new.
>>> lister := container getComponentInstance( MovieLister ).
>>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>>> self assert: (movies includes: 'Once Upon a Time in the West')
>>>
>>> The article poorly defines registerComponentXXX: or getComponentInstance:
>>> methods, so I don't dwell on them. I presume its little relevant to the
>>> main theme.
>>>
>>>
>>> ##SETTER INJECTION
>>>
>>> MovieLister >> setFinder: aFinder
>>> finder := aFinder.
>>>
>>> ColonMovieFinder >> setFilename: aFilename
>>> filename := aFilename.
>>>
>>> SetterInjectionTest >> testWithConfigurationFile
>>> ctx := SomeXmlApplicationConfiguration on: 'config.xml'.
>>> lister := ctx getConfigOf: 'MovieLister'.
>>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>>> self assert: (movies includes: 'Once Upon a Time in the West')
>>>
>>>
>>> ##INTERFACE INJECTION
>>>
>>> MovieLister >> injectFinder: aFinder
>>> finder := aFinder
>>>
>>> ColonMovieFinder >> injectFilename: aFilename
>>> filename := aFilename
>>>
>>> InterfaceInjectionTest >> configureContainer
>>> container := InterfaceInjectionContainer new.
>>> self registerComponents.
>>> self registerInjectors.
>>> container start.
>>>
>>> InterfaceInjectionTest >> registerComponents
>>> container registerComponent: 'MovieLister' with: MovieLister.
>>> container registerComponent: 'MovieFinder' with: ColonMovieFinder.
>>>
>>> InterfaceInjectionTest >> registerInjectors
>>> container registerInjector: Injector with: (container lookup:
>>> 'MovieFinder').
>>> container registerInjector: InjectorFinderFilename with:
>>> FinderFilenameInjector new.
>>>
>>> ColonMovieFinder >> inject: anObject
>>> anObject injectFinder: self.
>>>
>>> FinderFilenameInjector >> inject: anObject
>>> anObject injectFilename: 'movies1.txt'.
>>>
>>> InterfaceInjectionTester >> testInterface
>>> self configureContainer.
>>> lister := container lookup: 'MovieLister'.
>>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>>> self assert: (movies includes: 'Once Upon a Time in the West')
>>>
>>> The article doesn't define InterfaceInjectionContainer, but I guess it
>>> could look like this...
>>>
>>> InterfaceInjectionContainer >> registerComponent: componentName with:
>>> aComponent
>>> container ifNil: [ container := Dictionary new].
>>> container at: componentName put: aComponent
>>>
>>> InterfaceInjectionContainer >> lookup: componentName
>>> ^ container at: componentName
>>>
>>>
>>> ##SERVICE LOCATOR
>>>
>>> "The basic idea behind a service locator is to have an object that knows
>>> how to get hold of all of the services that an application might need. So a
>>> service locator for this application would have a method that returns a
>>> movie finder when one is needed. Of course this just shifts the burden a
>>> tad, we still have to get the locator into the lister"
>>>
>>> MovieLister >> initialize
>>> finder := ServiceLocator movieFinder.
>>>
>>>
>>> Object subclass: ServiceLocator
>>> instanceVariable: 'movieFinder'
>>> classVariable: 'SoleInstance'
>>>
>>> ServiceLocator class >> load: aServiceLocator
>>> SoleInstance := aServiceLocator
>>>
>>> ServiceLocator class >> soleInstance
>>> ^ SoleInstance
>>>
>>> ServiceLocator class >> movieFinder
>>> ^ self soleInstance movieFinder
>>>
>>> ServiceLocator >> movieFinder
>>> ^movieFinder
>>>
>>>
>>> ServiceLocatorTest >> configure
>>> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
>>> newWith: 'movies1.txt'))
>>>
>>>
>>> ServiceLocator class >> newWith: aMovieFinder
>>> ^ self basicNew initializeWithFinder: aMovieFinder
>>>
>>> ServiceLocator >> initializeWithFinder: aMovieFinder
>>> movieFinder := aMovieFinder
>>>
>>>
>>> ServiceLocatorTest >> testSimple
>>> self configure.
>>> lister := MovieLister new.
>>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>>> self assert: (movies includes: 'Once Upon a Time in the West')
>>>
>>> So it seems that a service locator is just a Singleton pattern having a
>>> class variable for each service of interest ??
>>>
>>
> It was late and I mispoke here, of course this should have said...
> * a Singleton pattern having an instance variable for each service of
> interest
> * a Singleton pattern having a getter method (with hidden implementation) for
> each service of interest
>
>
>
>> So in good faith** I ask... "Is it any more complicated than that?"
>>>
>>> **Since its taken me a couple of hours to convert the Java to this point
>>> so I stopped reading to seek your feedback.
>>>
>>
> but I'll add, it was so much simpler to understand without all that Java
> typing boiler plate.
>
> cheers -ben
>
>
>> Is that enough insight to adapt to your needs, or is there something else
>>> further down the article that invalidates my analysis?
>>>
>>>
>>>
>>>
>>>
>>>>
>>>> From ben:
>>>>
>>>> "I'm not really familiar with IoC or DI patterns, so just taking your
>>>>> example at face value, in Pharo I'd do...
>>>>>
>>>>> MovieLister>>moviesDirectedBy: director
>>>>> allMovies := finder allMovies.
>>>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>>>> "although typically #getDirector would be renamed #director"
>>>>>
>>>>> MovieLister>>finder: movieFinder
>>>>> finder := movieFinder.
>>>>>
>>>>> to be used like this...
>>>>> lister := MovieLister new finder: (ColonDelimitedMovieFinder on:
>>>>> 'movies1.txt').
>>>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>>>
>>>>
>>>
>>> So per Fowler, the above is equivalent to "Setter Injection with Spring"
>>>
>>>
>>>>
>>>> and Stephane:
>>>>
>>>> Why don't you simply pass the class and use that class in your
>>>>> MovieLister?
>>>>>
>>>>> MovieLister new
>>>>> finderClass: MySuperCoolFinderClass
>>>>>
>>>>> ...
>>>>> MovieLister finder
>>>>> finderClass new .....
>>>>>
>>>>> What is wrong with that.
>>>>
>>>>
>>>> That was what I meant when I said: "I know that in Smalltalk I can
>>>> make MovieLister to receive, upon construction, a class representing
>>>> MovieFinder and call it construction message.". The code I had in mind
>>>> is a bit of mix from the one provided by you both:
>>>>
>>>> MovieLister>>moviesDirectedBy: director
>>>> allMovies := finder allMovies.
>>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>>> "although typically #getDirector would be renamed #director"
>>>>
>>>> MovieLister>>finder: aMovieFinderBuilder
>>>> finder := aMovieFinderClass new.
>>>>
>>>> to be used like this...
>>>> lister := MovieLister new finder: (ColonDelimitedMovieFinder
>>>> builderOn: 'movies1.txt').
>>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>>>
>>>> But that means I will have to wire dependencies by hand whenever I
>>>> create a MovieLister and seek through code when and if those dependencies
>>>> change. When there are lot's of dependencies it's is a considerable and
>>>> tedious work. Let's see an image from Fowlers article:
>>>>
>>>> [image: Inline image 1]
>>>>
>>>> In this case, the service locator provides me with an instance and I
>>>> configure the instance in the assembler, the scheme is alike for an IoC,
>>>> and that would mean my implementation could be like this:
>>>>
>>>>
>>>> MovieLister>>moviesDirectedBy: director
>>>> allMovies := finder allMovies.
>>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>>> "although typically #getDirector would be renamed #director"
>>>>
>>>> MovieLister>>initialize
>>>> finder := ServiceLocator locate: FinderClass <--- This would
>>>> bring the instance of finder class configured by the assembler
>>>>
>>>
>>> No, like this...
>>> finder := ServiceLocation movieFinder.
>>>
>>> Now if you want to store a class rather than an instance as I did higher
>>> up, you just do this...
>>>
>>> Object subclass: ServiceLocator
>>> instanceVariable: 'movieFinderClass'
>>> classVariable: 'SoleInstance'
>>>
>>> ServiceLocator class >> movieFinder
>>> ^ self soleInstance movieFinderClass new
>>>
>>>
>>>
>>>>
>>>>
>>>> to be used like this...
>>>> lister := MovieLister new.
>>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>>>
>>>> and the assembler:
>>>>
>>>> Assember class>>configure:
>>>> aMap put: (ColonDelimitedMovieFinder builderOn: 'movies1.txt') at:
>>>> FinderClass
>>>>
>>>
>>> Assembler class>>configure
>>> ServiceLocator load:
>>> (ServiceLocator new
>>> movieFinder: (ColonMovieFinder newWith: 'movies1.txt')
>>> otherService: MyCustomService new)
>>>
>>>
>>>>
>>>> My assembler and service locator could be even more elaborated, and
>>>> provide a different MovieFinder in test scope, for different classes or
>>>> wharever.
>>>>
>>>
>>> Really, the test should not be updating the class variable global like
>>> this...
>>> ServiceLocatorTest >> configure
>>> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
>>> newWith: 'movies1.txt'))
>>>
>>> you probably want something like (its rough but shows the point...)
>>> Object subclass: #MovieLister
>>> instanceVariables: 'serviceLocator'
>>>
>>> MovieLister >> initialize
>>> serviceLocator ifNil: [ serviceLocator := ServiceLocator
>>> soleInstance ].
>>> finder := serviceLocator movieFinder.
>>>
>>> MovieLister class >> newWithServiceLocator: aServiceLocator
>>> ^ (self basicNew initializeWithServiceLocator: aServiceLocator)
>>> initialize.
>>>
>>> MovieLister >> initializeWithServiceLocator: aServiceLocator
>>> serviceLocator := aServiceLocator
>>>
>>> ServiceLocatorTest >> testSimple2
>>> lister := MovieLister newWithServiceLocator: (ServiceLocator
>>> newWith: (ColonMovieFinder newWith: 'movies1.txt')).
>>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>>> self assert: (movies includes: 'Once Upon a Time in the West')
>>>
>>>
>>> cheers -ben
>>>
>>>
>>>>
>>>> It is a little convenience for Smalltalk, I will give that, but I was
>>>> wandering if there was something alike in Pharo, by your answers I assuming
>>>> there is nothing like that.
>>>>
>>>>
>>>>
>>>> On Mon, Jun 5, 2017 at 6:41 AM, Stephane Ducasse <
>>>> stepharo.self(a)gmail.com> wrote:
>>>>
>>>>> Why don't you simply pass the class and use that class in your
>>>>> MovieLister?
>>>>>
>>>>> MovieLister new
>>>>> finderClass: MySuperCoolFinderClass
>>>>>
>>>>> ...
>>>>> MovieLister finder
>>>>> finderClass new .....
>>>>>
>>>>> What is wrong with that.
>>>>>
>>>>> If you do not want to have a reference at runtime to a Finder then you
>>>>> need to use announcement and registration.
>>>>>
>>>>> Stef
>>>>>
>>>>>
>>>>>
>>>>> On Sun, Jun 4, 2017 at 11:17 PM, Vitor Medina Cruz <
>>>>> vitormcruz(a)gmail.com> wrote:
>>>>> > Hello,
>>>>> >
>>>>> > I would like to know how people in Pharo ecosystem do to deal with
>>>>> object
>>>>> > wiring, as described by Marting Fowler in
>>>>> > https://martinfowler.com/articles/injection.html#FormsOfDepe
>>>>> ndencyInjection:
>>>>> >
>>>>> > "A common issue to deal with is how to wire together different
>>>>> elements: how
>>>>> > do you fit together this web controller architecture with that
>>>>> database
>>>>> > interface backing when they were built by different teams with little
>>>>> > knowledge of each other."
>>>>> >
>>>>> > He gives an example, I will leave it in java as it is simple enough
>>>>> to
>>>>> > understand:
>>>>> >
>>>>> > "class MovieLister...
>>>>> >
>>>>> > public Movie[] moviesDirectedBy(String arg) {
>>>>> > List allMovies = finder.findAll();
>>>>> > for (Iterator it = allMovies.iterator(); it.hasNext();) {
>>>>> > Movie movie = (Movie) it.next();
>>>>> > if (!movie.getDirector().equals(arg)) it.remove();
>>>>> > }
>>>>> > return (Movie[]) allMovies.toArray(new
>>>>> Movie[allMovies.size()]);
>>>>> >
>>>>> > }"
>>>>> >
>>>>> > The question is how to provide the finder object in a decoupled
>>>>> matter, a
>>>>> > naive approach would be:
>>>>> >
>>>>> > " private MovieFinder finder;
>>>>> >
>>>>> > public MovieLister() {
>>>>> > finder = new ColonDelimitedMovieFinder("movies1.txt");
>>>>> >
>>>>> > }"
>>>>> >
>>>>> > Which couples the MovieLister to the specific
>>>>> ColonDelimitedMovieFinder
>>>>> > class.
>>>>> >
>>>>> > Fowler explains how to decouple using an IoC framework or a Service
>>>>> Locator.
>>>>> > In Java and .Net IoC is used most of the time. I Googled how this
>>>>> problem is
>>>>> > approached in Smalltalk/Pharo, and I generally I found answers "that
>>>>> is easy
>>>>> > to do in Smalltalk, so there is no need of a framework", what I miss
>>>>> is a
>>>>> > description on *how* to do that:
>>>>> >
>>>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>>>> > https://stackoverflow.com/questions/2684326/is-there-a-depen
>>>>> dency-injection-framework-for-smalltalk
>>>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>>>> /347477#347477
>>>>> >
>>>>> > I know that in Smalltalk I can make MovieLister to receive, upon
>>>>> > construction, a class representing MovieFinder and call it
>>>>> construction
>>>>> > message. As long an object that responds to this message is
>>>>> provided, I can
>>>>> > create as many derivations I want and the MovieLister will be
>>>>> decoupled from
>>>>> > the MovieFinder. That way, however, I still have to wire things by
>>>>> hand, and
>>>>> > I am not sure if this is what I am supposed to do in order to solve
>>>>> the
>>>>> > decouple problem.
>>>>> >
>>>>> > Can you explain me how this is done in Pharo? It's is usually wiring
>>>>> by
>>>>> > hand? Is there a simple construction that deals with the wiring
>>>>> problem that
>>>>> > I cannot foresee?
>>>>> >
>>>>> > Thanks in advance,
>>>>> > Vitor
>>>>> >
>>>>> >
>>>>> >
>>>>>
>>>>>
>>>>
>>>
>>
>
June 6, 2017
Re: [Pharo-users] [Pharo-dev] [ANN] Pharo Consortium New Bronze Member: Palantir Solutions
by Tudor Girba
Excellent news!
Doru
> On Jun 6, 2017, at 2:53 PM, Marcus Denker <marcus.denker(a)inria.fr> wrote:
>
> The Pharo Consortium is very happy to announce that Palantir Solutions
> has joined the Consortium as a Bronze Member.
>
> About
> - Palantir Solutions: https://www.petrovr.com
> - Pharo Consortium: http://consortium.pharo.org
>
> The goal of the Pharo Consortium is to allow companies and institutions to
> support the ongoing development and future of Pharo.
>
> Individuals can support Pharo via the Pharo Association:
>
> - http://association.pharo.org
>
--
www.tudorgirba.com
www.feenk.com
"Every thing should have the right to be different."
June 6, 2017
[ANN] Pharo Consortium New Bronze Member: Palantir Solutions
by Marcus Denker
The Pharo Consortium is very happy to announce that Palantir Solutions
has joined the Consortium as a Bronze Member.
About
- Palantir Solutions: https://www.petrovr.com
- Pharo Consortium: http://consortium.pharo.org
The goal of the Pharo Consortium is to allow companies and institutions to
support the ongoing development and future of Pharo.
Individuals can support Pharo via the Pharo Association:
- http://association.pharo.org
June 6, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by phil@highoctane.be
Check
https://medium.com/@i.oleks/interface-for-selecting-data-from-a-dataset-d7c…
https://medium.com/@i.oleks/an-example-of-test-driven-development-c9ce033f0…
Loading a dataframe from a dataset and then using transducers for a
transformation pipeline would be great.
DataFrame is part of Polymath.
https://github.com/PolyMathOrg/PolyMath
http://www.smalltalkhub.com/#!/~PolyMath/PolyMath
Phil
On Tue, Jun 6, 2017 at 1:09 PM, Steffen Märcker <merkste(a)web.de> wrote:
> Hi Phil,
>
> Coupling this with Olek's work on the DataFrame could really come handy.
>>
>
> I am new to this list. Could you please elaborate?
>
> Cheers!
> Steffen
>
>
>
> On Mon, Jun 5, 2017 at 9:14 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
>> wrote:
>>
>> Hi Steffen
>>>
>>>
>>> > The short answer is that the compact notation turned out to work much
>>> better
>>> > for me in my code, especially, if multiple transducers are involved.
>>> But
>>> > that's my personal taste. You can choose which suits you better. In
>>> fact,
>>> >
>>> > 1000 take.
>>> >
>>> > just sits on top and simply calls
>>> >
>>> > Take number: 1000.
>>>
>>> To me this is much much better.
>>>
>>>
>>> > If the need arises, we could of course factor the compact notation out
>>> into
>>> > a separate package.
>>> Good idea
>>>
>>> Btw, would you prefer (Take n: 1000) over (Take number:
>>> > 1000)?
>>>
>>> I tend to prefer explicit selector :)
>>>
>>>
>>> > Damien, you're right, I experimented with additional styles. Right now,
>>> we
>>> > already have in the basic Transducer package:
>>> >
>>> > (collection transduce: #squared map * 1000 take. "which is equal to"
>>> > (collection transduce: #squared map) transduce: 1000 take.
>>> >
>>> > Basically, one can split #transduce:reduce:init: into single calls of
>>> > #transduce:, #reduce:, and #init:, depending on the needs.
>>> > I also have an (unfinished) extension, that allows to write:
>>> >
>>> > (collection transduce map: #squared) take: 1000.
>>>
>>> To me this is much mre readable.
>>> I cannot and do not want to use the other forms.
>>>
>>>
>>> > This feels familiar, but becomes a bit hard to read if more than two
>>> steps
>>> > are needed.
>>> >
>>> > collection transduce
>>> > map: #squared;
>>> > take: 1000.
>>>
>>> Why this is would hard to read. We do that all the time everywhere.
>>>
>>>
>>> > I think, this alternative would reads nicely. But as the message chain
>>> has
>>> > to modify the underlying object (an eduction), very snaky side effects
>>> may
>>> > occur. E.g., consider
>>> >
>>> > eduction := collection transduce.
>>> > squared := eduction map: #squared.
>>> > take := squared take: 1000.
>>> >
>>> > Now, all three variables hold onto the same object, which first squares
>>> all
>>> > elements and than takes the first 1000.
>>>
>>> This is because the programmer did not understand what he did. No?
>>>
>>>
>>>
>>> Stef
>>>
>>> PS: I played with infinite stream and iteration back in 1993 in CLOS.
>>> Now I do not like to mix things because it breaks my flow of thinking.
>>>
>>>
>>> >
>>> > Best,
>>> > Steffen
>>> >
>>> >
>>> >
>>> >
>>> >
>>> > Am .06.2017, 21:28 Uhr, schrieb Damien Pollet
>>> > <damien.pollet+pharo(a)gmail.com>:
>>> >
>>> >> If I recall correctly, there is an alternate protocol that looks more
>>> like
>>> >> xtreams or the traditional select/collect iterations.
>>> >>
>>> >> On 2 June 2017 at 21:12, Stephane Ducasse <stepharo.self(a)gmail.com>
>>> wrote:
>>> >>
>>> >>> I have a design question
>>> >>>
>>> >>> why the library is implemented in functional style vs messages?
>>> >>> I do not see why this is needed. To my eyes the compact notation
>>> >>> goes against readibility of code and it feels ad-hoc in Smalltalk.
>>> >>>
>>> >>>
>>> >>> I really prefer
>>> >>>
>>> >>> square := Map function: #squared.
>>> >>> take := Take number: 1000.
>>> >>>
>>> >>> Because I know that I can read it and understand it.
>>> >>> From that perspective I prefer Xtreams.
>>> >>>
>>> >>> Stef
>>> >>>
>>> >>>
>>> >>>
>>> >>>
>>> >>>
>>> >>>
>>> >>>
>>> >>>
>>> >>>
>>> >>> On Wed, May 31, 2017 at 2:23 PM, Steffen Märcker <merkste(a)web.de>
>>> wrote:
>>> >>>
>>> >>>> Hi,
>>> >>>>
>>> >>>> I am the developer of the library 'Transducers' for VisualWorks. It
>>> was
>>> >>>> formerly known as 'Reducers', but this name was a poor choice. I'd
>>> like
>>> >>>> to
>>> >>>> port it to Pharo, if there is any interest on your side. I hope to
>>> learn
>>> >>>> more about Pharo in this process, since I am mainly a VW guy. And
>>> most
>>> >>>> likely, I will come up with a bunch of questions. :-)
>>> >>>>
>>> >>>> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be
>>> very
>>> >>>> happy to hear your optinions, questions and I hope we can start a
>>> >>>> fruitful
>>> >>>> discussion - even if there is not Pharo port yet.
>>> >>>>
>>> >>>> Best, Steffen
>>> >>>>
>>> >>>>
>>> >>>>
>>> >>>> Transducers are building blocks that encapsulate how to process
>>> elements
>>> >>>> of a data sequence independently of the underlying input and output
>>> >>>> source.
>>> >>>>
>>> >>>>
>>> >>>>
>>> >>>> # Overview
>>> >>>>
>>> >>>> ## Encapsulate
>>> >>>> Implementations of enumeration methods, such as #collect:, have the
>>> >>>> logic
>>> >>>> how to process a single element in common.
>>> >>>> However, that logic is reimplemented each and every time.
>>> Transducers
>>> >>>> make
>>> >>>> it explicit and facilitate re-use and coherent behavior.
>>> >>>> For example:
>>> >>>> - #collect: requires mapping: (aBlock1 map)
>>> >>>> - #select: requires filtering: (aBlock2 filter)
>>> >>>>
>>> >>>>
>>> >>>> ## Compose
>>> >>>> In practice, algorithms often require multiple processing steps,
>>> e.g.,
>>> >>>> mapping only a filtered set of elements.
>>> >>>> Transducers are inherently composable, and hereby, allow to make the
>>> >>>> combination of steps explicit.
>>> >>>> Since transducers do not build intermediate collections, their
>>> >>>> composition
>>> >>>> is memory-efficient.
>>> >>>> For example:
>>> >>>> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map
>>> elements"
>>> >>>>
>>> >>>>
>>> >>>> ## Re-Use
>>> >>>> Transducers are decoupled from the input and output sources, and
>>> hence,
>>> >>>> they can be reused in different contexts.
>>> >>>> For example:
>>> >>>> - enumeration of collections
>>> >>>> - processing of streams
>>> >>>> - communicating via channels
>>> >>>>
>>> >>>>
>>> >>>>
>>> >>>> # Usage by Example
>>> >>>>
>>> >>>> We build a coin flipping experiment and count the occurrence of
>>> heads
>>> >>>> and
>>> >>>> tails.
>>> >>>>
>>> >>>> First, we associate random numbers with the sides of a coin.
>>> >>>>
>>> >>>> scale := [:x | (x * 2 + 1) floor] map.
>>> >>>> sides := #(heads tails) replace.
>>> >>>>
>>> >>>> Scale is a transducer that maps numbers x between 0 and 1 to 1 and
>>> 2.
>>> >>>> Sides is a transducer that replaces the numbers with heads an tails
>>> by
>>> >>>> lookup in an array.
>>> >>>> Next, we choose a number of samples.
>>> >>>>
>>> >>>> count := 1000 take.
>>> >>>>
>>> >>>> Count is a transducer that takes 1000 elements from a source.
>>> >>>> We keep track of the occurrences of heads an tails using a bag.
>>> >>>>
>>> >>>> collect := [:bag :c | bag add: c; yourself].
>>> >>>>
>>> >>>> Collect is binary block (reducing function) that collects events in
>>> a
>>> >>>> bag.
>>> >>>> We assemble the experiment by transforming the block using the
>>> >>>> transducers.
>>> >>>>
>>> >>>> experiment := (scale * sides * count) transform: collect.
>>> >>>>
>>> >>>> From left to right we see the steps involved: scale, sides, count
>>> and
>>> >>>> collect.
>>> >>>> Transforming assembles these steps into a binary block (reducing
>>> >>>> function)
>>> >>>> we can use to run the experiment.
>>> >>>>
>>> >>>> samples := Random new
>>> >>>> reduce: experiment
>>> >>>> init: Bag new.
>>> >>>>
>>> >>>> Here, we use #reduce:init:, which is mostly similar to
>>> #inject:into:.
>>> >>>> To execute a transformation and a reduction together, we can use
>>> >>>> #transduce:reduce:init:.
>>> >>>>
>>> >>>> samples := Random new
>>> >>>> transduce: scale * sides * count
>>> >>>> reduce: collect
>>> >>>> init: Bag new.
>>> >>>>
>>> >>>> We can also express the experiment as data-flow using #<~.
>>> >>>> This enables us to build objects that can be re-used in other
>>> >>>> experiments.
>>> >>>>
>>> >>>> coin := sides <~ scale <~ Random new.
>>> >>>> flip := Bag <~ count.
>>> >>>>
>>> >>>> Coin is an eduction, i.e., it binds transducers to a source and
>>> >>>> understands #reduce:init: among others.
>>> >>>> Flip is a transformed reduction, i.e., it binds transducers to a
>>> >>>> reducing
>>> >>>> function and an initial value.
>>> >>>> By sending #<~, we draw further samples from flipping the coin.
>>> >>>>
>>> >>>> samples := flip <~ coin.
>>> >>>>
>>> >>>> This yields a new Bag with another 1000 samples.
>>> >>>>
>>> >>>>
>>> >>>>
>>> >>>> # Basic Concepts
>>> >>>>
>>> >>>> ## Reducing Functions
>>> >>>>
>>> >>>> A reducing function represents a single step in processing a data
>>> >>>> sequence.
>>> >>>> It takes an accumulated result and a value, and returns a new
>>> >>>> accumulated
>>> >>>> result.
>>> >>>> For example:
>>> >>>>
>>> >>>> collect := [:col :e | col add: e; yourself].
>>> >>>> sum := #+.
>>> >>>>
>>> >>>> A reducing function can also be ternary, i.e., it takes an
>>> accumulated
>>> >>>> result, a key and a value.
>>> >>>> For example:
>>> >>>>
>>> >>>> collect := [:dic :k :v | dict at: k put: v; yourself].
>>> >>>>
>>> >>>> Reducing functions may be equipped with an optional completing
>>> action.
>>> >>>> After finishing processing, it is invoked exactly once, e.g., to
>>> free
>>> >>>> resources.
>>> >>>>
>>> >>>> stream := [:str :e | str nextPut: each; yourself] completing:
>>> >>>> #close.
>>> >>>> absSum := #+ completing: #abs
>>> >>>>
>>> >>>> A reducing function can end processing early by signaling Reduced
>>> with a
>>> >>>> result.
>>> >>>> This mechanism also enables the treatment of infinite sources.
>>> >>>>
>>> >>>> nonNil := [:res :e | e ifNil: [Reduced signalWith: res] ifFalse:
>>> >>>> [res]].
>>> >>>>
>>> >>>> The primary approach to process a data sequence is the reducing
>>> protocol
>>> >>>> with the messages #reduce:init: and #transduce:reduce:init: if
>>> >>>> transducers
>>> >>>> are involved.
>>> >>>> The behavior is similar to #inject:into: but in addition it takes
>>> care
>>> >>>> of:
>>> >>>> - handling binary and ternary reducing functions,
>>> >>>> - invoking the completing action after finishing, and
>>> >>>> - stopping the reduction if Reduced is signaled.
>>> >>>> The message #transduce:reduce:init: just combines the transformation
>>> and
>>> >>>> the reducing step.
>>> >>>>
>>> >>>> However, as reducing functions are step-wise in nature, an
>>> application
>>> >>>> may
>>> >>>> choose other means to process its data.
>>> >>>>
>>> >>>>
>>> >>>> ## Reducibles
>>> >>>>
>>> >>>> A data source is called reducible if it implements the reducing
>>> >>>> protocol.
>>> >>>> Default implementations are provided for collections and streams.
>>> >>>> Additionally, blocks without an argument are reducible, too.
>>> >>>> This allows to adapt to custom data sources without additional
>>> effort.
>>> >>>> For example:
>>> >>>>
>>> >>>> "XStreams adaptor"
>>> >>>> xstream := filename reading.
>>> >>>> reducible := [[xstream get] on: Incomplete do: [Reduced
>>> signal]].
>>> >>>>
>>> >>>> "natural numbers"
>>> >>>> n := 0.
>>> >>>> reducible := [n := n+1].
>>> >>>>
>>> >>>>
>>> >>>> ## Transducers
>>> >>>>
>>> >>>> A transducer is an object that transforms a reducing function into
>>> >>>> another.
>>> >>>> Transducers encapsulate common steps in processing data sequences,
>>> such
>>> >>>> as
>>> >>>> map, filter, concatenate, and flatten.
>>> >>>> A transducer transforms a reducing function into another via
>>> #transform:
>>> >>>> in order to add those steps.
>>> >>>> They can be composed using #* which yields a new transducer that
>>> does
>>> >>>> both
>>> >>>> transformations.
>>> >>>> Most transducers require an argument, typically blocks, symbols or
>>> >>>> numbers:
>>> >>>>
>>> >>>> square := Map function: #squared.
>>> >>>> take := Take number: 1000.
>>> >>>>
>>> >>>> To facilitate compact notation, the argument types implement
>>> >>>> corresponding
>>> >>>> methods:
>>> >>>>
>>> >>>> squareAndTake := #squared map * 1000 take.
>>> >>>>
>>> >>>> Transducers requiring no argument are singletons and can be accessed
>>> by
>>> >>>> their class name.
>>> >>>>
>>> >>>> flattenAndDedupe := Flatten * Dedupe.
>>> >>>>
>>> >>>>
>>> >>>>
>>> >>>> # Advanced Concepts
>>> >>>>
>>> >>>> ## Data flows
>>> >>>>
>>> >>>> Processing a sequence of data can often be regarded as a data flow.
>>> >>>> The operator #<~ allows define a flow from a data source through
>>> >>>> processing steps to a drain.
>>> >>>> For example:
>>> >>>>
>>> >>>> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
>>> >>>> fileOut writeStream <~ #isSeparator filter <~ fileIn readStream.
>>> >>>>
>>> >>>> In both examples #<~ is only used to set up the data flow using
>>> reducing
>>> >>>> functions and transducers.
>>> >>>> In contrast to streams, transducers are completely independent from
>>> >>>> input
>>> >>>> and output sources.
>>> >>>> Hence, we have a clear separation of reading data, writing data and
>>> >>>> processing elements.
>>> >>>> - Sources know how to iterate over data with a reducing function,
>>> e.g.,
>>> >>>> via #reduce:init:.
>>> >>>> - Drains know how to collect data using a reducing function.
>>> >>>> - Transducers know how to process single elements.
>>> >>>>
>>> >>>>
>>> >>>> ## Reductions
>>> >>>>
>>> >>>> A reduction binds an initial value or a block yielding an initial
>>> value
>>> >>>> to
>>> >>>> a reducing function.
>>> >>>> The idea is to define a ready-to-use process that can be applied in
>>> >>>> different contexts.
>>> >>>> Reducibles handle reductions via #reduce: and #transduce:reduce:
>>> >>>> For example:
>>> >>>>
>>> >>>> sum := #+ init: 0.
>>> >>>> sum1 := #(1 1 1) reduce: sum.
>>> >>>> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
>>> >>>>
>>> >>>> asSet := [:set :e | set add: e; yourself] initializer: [Set
>>> new].
>>> >>>> set1 := #(1 1 1) reduce: asSet.
>>> >>>> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
>>> >>>>
>>> >>>> By combining a transducer with a reduction, a process can be further
>>> >>>> modified.
>>> >>>>
>>> >>>> sumOdds := sum <~ #odd filter
>>> >>>> setOdds := asSet <~ #odd filter
>>> >>>>
>>> >>>>
>>> >>>> ## Eductions
>>> >>>>
>>> >>>> An eduction combines a reducible data sources with a transducer.
>>> >>>> The idea is to define a transformed (virtual) data source that needs
>>> not
>>> >>>> to be stored in memory.
>>> >>>>
>>> >>>> odds1 := #odd filter <~ #(1 2 3) readStream.
>>> >>>> odds2 := #odd filter <~ (1 to 1000).
>>> >>>>
>>> >>>> Depending on the underlying source, eductions can be processed once
>>> >>>> (streams, e.g., odds1) or multiple times (collections, e.g., odds2).
>>> >>>> Since no intermediate data is stored, transducers actions are lazy,
>>> >>>> i.e.,
>>> >>>> they are invoked each time the eduction is processed.
>>> >>>>
>>> >>>>
>>> >>>>
>>> >>>> # Origins
>>> >>>>
>>> >>>> Transducers is based on the same-named Clojure library and its
>>> ideas.
>>> >>>> Please see:
>>> >>>> http://clojure.org/transducers
>>> >>>>
>>> >>>>
>>> >
>>>
>>>
>>>
>
>
June 6, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by phil@highoctane.be
Hi Steffen,
I am willing to help you create the package in SmalltalkHub or Github based
on your files/changeset.
Do you have a github and/or SmalltalkHub account?
Best,
Phil
On Tue, Jun 6, 2017 at 1:08 PM, Steffen Märcker <merkste(a)web.de> wrote:
> Hi!
>
> If the need arises, we could of course factor the compact notation out into
>>> a separate package.
>>>
>> Good idea
>> [...] I do not want to help promoting a syntax that alienates me (and
>> others because other people reported the saem to me).
>>
>
> I understand. Btw, I'd really, really appreciate if others post their
> thoughts and feedback here as well. Discussion helps moving things forward.
> =)
>
>
> (collection transduce map: #squared) take: 1000.
>>>
>>
>> To me this is much more readable.
>>
>
> Well, I'll provide that extension once it is finished.
>
> I cannot and do not want to use the other forms.
>>
>
>
> collection transduce
>>> map: #squared;
>>> take: 1000.
>>>
>>> But as the message chain has to modify the underlying object
>>> (an eduction), very snaky side effects my occur. E.g., consider
>>>
>>> eduction := collection transduce.
>>> squared := eduction map: #squared.
>>> take := squared take: 1000.
>>>
>>> Now, all three variables hold onto the same object, which first squares
>>> all elements and than takes the first 1000.
>>>
>>
>> This is because the programmer did not understand what he did. No?
>>
>
> Sure. ;-) Nevertheless, it would be very hard to debug. All of which are
> the reasons I wouldn't implement that variant. ;-)
>
>
> PS: I played with infinite stream and iteration back in 1993 in CLOS.
>> Now I do not like to mix things because it breaks my flow of thinking.
>>
>
>
> I am not sure whether I understand what your mean by mixing. Concerning
> transducers, the ability to handle infinite sources in only a (natural)
> side-effect of the ability to finish reductions before all elements are
> processed, e.g., like #detect: and such.
>
> Best, Steffen
>
>
>
>
>
>
June 6, 2017
Re: [Pharo-users] Creating a BaselineOf from a ConfigurationOf>>#baselineXyz:
by Nicolai Hess
Hi Sean,
2017-06-04 5:48 GMT+02:00 Sean P. DeNigris <sean(a)clipperadams.com>:
> I'm trying to write a rewrite rule, but can't quite get it.
>
> I first want to remove `spec blessing: #baseline.`
>
> I tried the following with no effect:
>
> RBParseTreeRewriter new
> replace: '`@expr blessing: `#lit'
> with: '';
> executeTree: methodTree;
> tree.
>
This works for me, but ...
>
> NB: If I try to edit the expression instead of remove, by passing something
> like '`@expr assert: `#lit' for #with:, it works
>
> What am I missing here?
>
> Thanks!
>
>
keep in mind some odds about the caching on ast nodes.
Working with the tree rewriter directly on the method ast
(MyClass>>#myMethod) ast
- will modify the "cached" method ast, that means, on code browser, you
do not see the change.
- the #source method of the ast, again only shows a cached source
(MyClass>>#myMethod) ast source -> "old source"
- printing the formatted code will finally step into the (modified) method
source nodes
(MyClass>>#myMethod) ast formattedCode -> "new source code"
>
>
> -----
> Cheers,
> Sean
> --
> View this message in context: http://forum.world.st/
> Creating-a-BaselineOf-from-a-ConfigurationOf-baselineXyz-tp4949192.html
> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>
>
June 6, 2017
Re: [Pharo-users] Analyzing Fuel Problem
by Mariano Martinez Peck
Hi Sean,
Sorry for the delay on the answer. Yes, that's a good spot. Another thing I
usually do is to put a halt in FLSerialization >> run. Just after
#analysisStep for example, and then inspect the local variables.
Also, if you want to understand WHY an object is getting in, then you can
also halt in #trace and #privateTrace: from FLAnalysis. That way you
monitor which objects gets pushed into the analysis stack. You can do
something like
self haltIf: [ anObject whateverConditionToHaltOnDesiredObject = true ].
Finally, there are more tools for debugging this kind of issue, but I don't
know their state. You can read more about them here [1].
Best regards,
[1]
https://rmod.inria.fr/web/software/Fuel/Version1.9/Documentation/Debugging
On Fri, Jun 2, 2017 at 10:26 PM, Sean P. DeNigris <sean(a)clipperadams.com>
wrote:
> I had an object graph that was pulling in all sorts of unrelated classes
> when
> serialized with Fuel. I was trying to find the offending object, and came
> up
> with the following:
> ```
> (FLAnalyzer newDefault analysisFor: root) clusterization globalsBucket
> ```
>
> This worked, but I was wondering if that's "the right way" to do it...
>
> Thanks.
>
>
>
> -----
> Cheers,
> Sean
> --
> View this message in context: http://forum.world.st/
> Analyzing-Fuel-Problem-tp4949104.html
> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>
>
--
Mariano
http://marianopeck.wordpress.com
June 6, 2017
Re: [Pharo-users] Porting Transducers to Pharo - Name Clash
by Steffen Märcker
Hi,
I found some name clash with the message #reduce: in Pharo. It is already
declared in SequencableCollection. Additionally, Collection>>fold: just
calls #reduce:, which makes the difference between folding and reducing a
bit unclear.
How should I handle this situation? I see the following options:
- I could simply solve the situation at runtime depending on the argument
(e.g., using double-dispatching).
- I could check whether it might be possible to separate #fold: and
#reduce: with the semantics:
- reduce: starts with an initial value and the first collection item.
- fold: uses no initial value and starts with the first two items.
In the Transducers library, there are two variants of reduce:
- #reduce:init: reduce using a block and an intial value
- #reduce: reduce using a block that carries an intial value or an
initializer block.
Ciao,
Steffen
Am .05.2017, 14:23 Uhr, schrieb Steffen Märcker <merkste(a)web.de>:
> Hi,
>
> I am the developer of the library 'Transducers' for VisualWorks. It was
> formerly known as 'Reducers', but this name was a poor choice. I'd like
> to port it to Pharo, if there is any interest on your side. I hope to
> learn more about Pharo in this process, since I am mainly a VW guy. And
> most likely, I will come up with a bunch of questions. :-)
>
> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be very
> happy to hear your optinions, questions and I hope we can start a
> fruitful discussion - even if there is not Pharo port yet.
>
> Best, Steffen
>
>
>
> Transducers are building blocks that encapsulate how to process elements
> of a data sequence independently of the underlying input and output
> source.
>
>
>
> # Overview
>
> ## Encapsulate
> Implementations of enumeration methods, such as #collect:, have the logic
> how to process a single element in common.
> However, that logic is reimplemented each and every time. Transducers
> make
> it explicit and facilitate re-use and coherent behavior.
> For example:
> - #collect: requires mapping: (aBlock1 map)
> - #select: requires filtering: (aBlock2 filter)
>
>
> ## Compose
> In practice, algorithms often require multiple processing steps, e.g.,
> mapping only a filtered set of elements.
> Transducers are inherently composable, and hereby, allow to make the
> combination of steps explicit.
> Since transducers do not build intermediate collections, their
> composition
> is memory-efficient.
> For example:
> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map elements"
>
>
> ## Re-Use
> Transducers are decoupled from the input and output sources, and hence,
> they can be reused in different contexts.
> For example:
> - enumeration of collections
> - processing of streams
> - communicating via channels
>
>
>
> # Usage by Example
>
> We build a coin flipping experiment and count the occurrence of heads and
> tails.
>
> First, we associate random numbers with the sides of a coin.
>
> scale := [:x | (x * 2 + 1) floor] map.
> sides := #(heads tails) replace.
>
> Scale is a transducer that maps numbers x between 0 and 1 to 1 and 2.
> Sides is a transducer that replaces the numbers with heads an tails by
> lookup in an array.
> Next, we choose a number of samples.
>
> count := 1000 take.
>
> Count is a transducer that takes 1000 elements from a source.
> We keep track of the occurrences of heads an tails using a bag.
>
> collect := [:bag :c | bag add: c; yourself].
>
> Collect is binary block (reducing function) that collects events in a
> bag.
> We assemble the experiment by transforming the block using the
> transducers.
>
> experiment := (scale * sides * count) transform: collect.
>
> From left to right we see the steps involved: scale, sides, count and
> collect.
> Transforming assembles these steps into a binary block (reducing
> function)
> we can use to run the experiment.
>
> samples := Random new
> reduce: experiment
> init: Bag new.
>
> Here, we use #reduce:init:, which is mostly similar to #inject:into:.
> To execute a transformation and a reduction together, we can use
> #transduce:reduce:init:.
>
> samples := Random new
> transduce: scale * sides * count
> reduce: collect
> init: Bag new.
>
> We can also express the experiment as data-flow using #<~.
> This enables us to build objects that can be re-used in other
> experiments.
>
> coin := sides <~ scale <~ Random new.
> flip := Bag <~ count.
>
> Coin is an eduction, i.e., it binds transducers to a source and
> understands #reduce:init: among others.
> Flip is a transformed reduction, i.e., it binds transducers to a reducing
> function and an initial value.
> By sending #<~, we draw further samples from flipping the coin.
>
> samples := flip <~ coin.
>
> This yields a new Bag with another 1000 samples.
>
>
>
> # Basic Concepts
>
> ## Reducing Functions
>
> A reducing function represents a single step in processing a data
> sequence.
> It takes an accumulated result and a value, and returns a new accumulated
> result.
> For example:
>
> collect := [:col :e | col add: e; yourself].
> sum := #+.
>
> A reducing function can also be ternary, i.e., it takes an accumulated
> result, a key and a value.
> For example:
>
> collect := [:dic :k :v | dict at: k put: v; yourself].
>
> Reducing functions may be equipped with an optional completing action.
> After finishing processing, it is invoked exactly once, e.g., to free
> resources.
>
> stream := [:str :e | str nextPut: each; yourself] completing:
> #close.
> absSum := #+ completing: #abs
>
> A reducing function can end processing early by signaling Reduced with a
> result.
> This mechanism also enables the treatment of infinite sources.
>
> nonNil := [:res :e | e ifNil: [Reduced signalWith: res] ifFalse:
> [res]].
>
> The primary approach to process a data sequence is the reducing protocol
> with the messages #reduce:init: and #transduce:reduce:init: if
> transducers
> are involved.
> The behavior is similar to #inject:into: but in addition it takes care
> of:
> - handling binary and ternary reducing functions,
> - invoking the completing action after finishing, and
> - stopping the reduction if Reduced is signaled.
> The message #transduce:reduce:init: just combines the transformation and
> the reducing step.
>
> However, as reducing functions are step-wise in nature, an application
> may
> choose other means to process its data.
>
>
> ## Reducibles
>
> A data source is called reducible if it implements the reducing protocol.
> Default implementations are provided for collections and streams.
> Additionally, blocks without an argument are reducible, too.
> This allows to adapt to custom data sources without additional effort.
> For example:
>
> "XStreams adaptor"
> xstream := filename reading.
> reducible := [[xstream get] on: Incomplete do: [Reduced signal]].
>
> "natural numbers"
> n := 0.
> reducible := [n := n+1].
>
>
> ## Transducers
>
> A transducer is an object that transforms a reducing function into
> another.
> Transducers encapsulate common steps in processing data sequences, such
> as
> map, filter, concatenate, and flatten.
> A transducer transforms a reducing function into another via #transform:
> in order to add those steps.
> They can be composed using #* which yields a new transducer that does
> both
> transformations.
> Most transducers require an argument, typically blocks, symbols or
> numbers:
>
> square := Map function: #squared.
> take := Take number: 1000.
>
> To facilitate compact notation, the argument types implement
> corresponding
> methods:
>
> squareAndTake := #squared map * 1000 take.
>
> Transducers requiring no argument are singletons and can be accessed by
> their class name.
>
> flattenAndDedupe := Flatten * Dedupe.
>
>
>
> # Advanced Concepts
>
> ## Data flows
>
> Processing a sequence of data can often be regarded as a data flow.
> The operator #<~ allows define a flow from a data source through
> processing steps to a drain.
> For example:
>
> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
> fileOut writeStream <~ #isSeparator filter <~ fileIn readStream.
>
> In both examples #<~ is only used to set up the data flow using reducing
> functions and transducers.
> In contrast to streams, transducers are completely independent from input
> and output sources.
> Hence, we have a clear separation of reading data, writing data and
> processing elements.
> - Sources know how to iterate over data with a reducing function, e.g.,
> via #reduce:init:.
> - Drains know how to collect data using a reducing function.
> - Transducers know how to process single elements.
>
>
> ## Reductions
>
> A reduction binds an initial value or a block yielding an initial value
> to
> a reducing function.
> The idea is to define a ready-to-use process that can be applied in
> different contexts.
> Reducibles handle reductions via #reduce: and #transduce:reduce:
> For example:
>
> sum := #+ init: 0.
> sum1 := #(1 1 1) reduce: sum.
> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
>
> asSet := [:set :e | set add: e; yourself] initializer: [Set new].
> set1 := #(1 1 1) reduce: asSet.
> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
>
> By combining a transducer with a reduction, a process can be further
> modified.
>
> sumOdds := sum <~ #odd filter
> setOdds := asSet <~ #odd filter
>
>
> ## Eductions
>
> An eduction combines a reducible data sources with a transducer.
> The idea is to define a transformed (virtual) data source that needs not
> to be stored in memory.
>
> odds1 := #odd filter <~ #(1 2 3) readStream.
> odds2 := #odd filter <~ (1 to 1000).
>
> Depending on the underlying source, eductions can be processed once
> (streams, e.g., odds1) or multiple times (collections, e.g., odds2).
> Since no intermediate data is stored, transducers actions are lazy, i.e.,
> they are invoked each time the eduction is processed.
>
>
>
> # Origins
>
> Transducers is based on the same-named Clojure library and its ideas.
> Please see:
> http://clojure.org/transducers
June 6, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Steffen Märcker
Hi Phil,
> Coupling this with Olek's work on the DataFrame could really come handy.
I am new to this list. Could you please elaborate?
Cheers!
Steffen
> On Mon, Jun 5, 2017 at 9:14 AM, Stephane Ducasse
> <stepharo.self(a)gmail.com>
> wrote:
>
>> Hi Steffen
>>
>>
>> > The short answer is that the compact notation turned out to work much
>> better
>> > for me in my code, especially, if multiple transducers are involved.
>> But
>> > that's my personal taste. You can choose which suits you better. In
>> fact,
>> >
>> > 1000 take.
>> >
>> > just sits on top and simply calls
>> >
>> > Take number: 1000.
>>
>> To me this is much much better.
>>
>>
>> > If the need arises, we could of course factor the compact notation out
>> into
>> > a separate package.
>> Good idea
>>
>> Btw, would you prefer (Take n: 1000) over (Take number:
>> > 1000)?
>>
>> I tend to prefer explicit selector :)
>>
>>
>> > Damien, you're right, I experimented with additional styles. Right
>> now,
>> we
>> > already have in the basic Transducer package:
>> >
>> > (collection transduce: #squared map * 1000 take. "which is equal to"
>> > (collection transduce: #squared map) transduce: 1000 take.
>> >
>> > Basically, one can split #transduce:reduce:init: into single calls of
>> > #transduce:, #reduce:, and #init:, depending on the needs.
>> > I also have an (unfinished) extension, that allows to write:
>> >
>> > (collection transduce map: #squared) take: 1000.
>>
>> To me this is much mre readable.
>> I cannot and do not want to use the other forms.
>>
>>
>> > This feels familiar, but becomes a bit hard to read if more than two
>> steps
>> > are needed.
>> >
>> > collection transduce
>> > map: #squared;
>> > take: 1000.
>>
>> Why this is would hard to read. We do that all the time everywhere.
>>
>>
>> > I think, this alternative would reads nicely. But as the message chain
>> has
>> > to modify the underlying object (an eduction), very snaky side effects
>> may
>> > occur. E.g., consider
>> >
>> > eduction := collection transduce.
>> > squared := eduction map: #squared.
>> > take := squared take: 1000.
>> >
>> > Now, all three variables hold onto the same object, which first
>> squares
>> all
>> > elements and than takes the first 1000.
>>
>> This is because the programmer did not understand what he did. No?
>>
>>
>>
>> Stef
>>
>> PS: I played with infinite stream and iteration back in 1993 in CLOS.
>> Now I do not like to mix things because it breaks my flow of thinking.
>>
>>
>> >
>> > Best,
>> > Steffen
>> >
>> >
>> >
>> >
>> >
>> > Am .06.2017, 21:28 Uhr, schrieb Damien Pollet
>> > <damien.pollet+pharo(a)gmail.com>:
>> >
>> >> If I recall correctly, there is an alternate protocol that looks more
>> like
>> >> xtreams or the traditional select/collect iterations.
>> >>
>> >> On 2 June 2017 at 21:12, Stephane Ducasse <stepharo.self(a)gmail.com>
>> wrote:
>> >>
>> >>> I have a design question
>> >>>
>> >>> why the library is implemented in functional style vs messages?
>> >>> I do not see why this is needed. To my eyes the compact notation
>> >>> goes against readibility of code and it feels ad-hoc in Smalltalk.
>> >>>
>> >>>
>> >>> I really prefer
>> >>>
>> >>> square := Map function: #squared.
>> >>> take := Take number: 1000.
>> >>>
>> >>> Because I know that I can read it and understand it.
>> >>> From that perspective I prefer Xtreams.
>> >>>
>> >>> Stef
>> >>>
>> >>>
>> >>>
>> >>>
>> >>>
>> >>>
>> >>>
>> >>>
>> >>>
>> >>> On Wed, May 31, 2017 at 2:23 PM, Steffen Märcker <merkste(a)web.de>
>> wrote:
>> >>>
>> >>>> Hi,
>> >>>>
>> >>>> I am the developer of the library 'Transducers' for VisualWorks. It
>> was
>> >>>> formerly known as 'Reducers', but this name was a poor choice. I'd
>> like
>> >>>> to
>> >>>> port it to Pharo, if there is any interest on your side. I hope to
>> learn
>> >>>> more about Pharo in this process, since I am mainly a VW guy. And
>> most
>> >>>> likely, I will come up with a bunch of questions. :-)
>> >>>>
>> >>>> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be
>> very
>> >>>> happy to hear your optinions, questions and I hope we can start a
>> >>>> fruitful
>> >>>> discussion - even if there is not Pharo port yet.
>> >>>>
>> >>>> Best, Steffen
>> >>>>
>> >>>>
>> >>>>
>> >>>> Transducers are building blocks that encapsulate how to process
>> elements
>> >>>> of a data sequence independently of the underlying input and output
>> >>>> source.
>> >>>>
>> >>>>
>> >>>>
>> >>>> # Overview
>> >>>>
>> >>>> ## Encapsulate
>> >>>> Implementations of enumeration methods, such as #collect:, have the
>> >>>> logic
>> >>>> how to process a single element in common.
>> >>>> However, that logic is reimplemented each and every time.
>> Transducers
>> >>>> make
>> >>>> it explicit and facilitate re-use and coherent behavior.
>> >>>> For example:
>> >>>> - #collect: requires mapping: (aBlock1 map)
>> >>>> - #select: requires filtering: (aBlock2 filter)
>> >>>>
>> >>>>
>> >>>> ## Compose
>> >>>> In practice, algorithms often require multiple processing steps,
>> e.g.,
>> >>>> mapping only a filtered set of elements.
>> >>>> Transducers are inherently composable, and hereby, allow to make
>> the
>> >>>> combination of steps explicit.
>> >>>> Since transducers do not build intermediate collections, their
>> >>>> composition
>> >>>> is memory-efficient.
>> >>>> For example:
>> >>>> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map
>> elements"
>> >>>>
>> >>>>
>> >>>> ## Re-Use
>> >>>> Transducers are decoupled from the input and output sources, and
>> hence,
>> >>>> they can be reused in different contexts.
>> >>>> For example:
>> >>>> - enumeration of collections
>> >>>> - processing of streams
>> >>>> - communicating via channels
>> >>>>
>> >>>>
>> >>>>
>> >>>> # Usage by Example
>> >>>>
>> >>>> We build a coin flipping experiment and count the occurrence of
>> heads
>> >>>> and
>> >>>> tails.
>> >>>>
>> >>>> First, we associate random numbers with the sides of a coin.
>> >>>>
>> >>>> scale := [:x | (x * 2 + 1) floor] map.
>> >>>> sides := #(heads tails) replace.
>> >>>>
>> >>>> Scale is a transducer that maps numbers x between 0 and 1 to 1 and
>> 2.
>> >>>> Sides is a transducer that replaces the numbers with heads an
>> tails by
>> >>>> lookup in an array.
>> >>>> Next, we choose a number of samples.
>> >>>>
>> >>>> count := 1000 take.
>> >>>>
>> >>>> Count is a transducer that takes 1000 elements from a source.
>> >>>> We keep track of the occurrences of heads an tails using a bag.
>> >>>>
>> >>>> collect := [:bag :c | bag add: c; yourself].
>> >>>>
>> >>>> Collect is binary block (reducing function) that collects events
>> in a
>> >>>> bag.
>> >>>> We assemble the experiment by transforming the block using the
>> >>>> transducers.
>> >>>>
>> >>>> experiment := (scale * sides * count) transform: collect.
>> >>>>
>> >>>> From left to right we see the steps involved: scale, sides, count
>> and
>> >>>> collect.
>> >>>> Transforming assembles these steps into a binary block (reducing
>> >>>> function)
>> >>>> we can use to run the experiment.
>> >>>>
>> >>>> samples := Random new
>> >>>> reduce: experiment
>> >>>> init: Bag new.
>> >>>>
>> >>>> Here, we use #reduce:init:, which is mostly similar to
>> #inject:into:.
>> >>>> To execute a transformation and a reduction together, we can use
>> >>>> #transduce:reduce:init:.
>> >>>>
>> >>>> samples := Random new
>> >>>> transduce: scale * sides * count
>> >>>> reduce: collect
>> >>>> init: Bag new.
>> >>>>
>> >>>> We can also express the experiment as data-flow using #<~.
>> >>>> This enables us to build objects that can be re-used in other
>> >>>> experiments.
>> >>>>
>> >>>> coin := sides <~ scale <~ Random new.
>> >>>> flip := Bag <~ count.
>> >>>>
>> >>>> Coin is an eduction, i.e., it binds transducers to a source and
>> >>>> understands #reduce:init: among others.
>> >>>> Flip is a transformed reduction, i.e., it binds transducers to a
>> >>>> reducing
>> >>>> function and an initial value.
>> >>>> By sending #<~, we draw further samples from flipping the coin.
>> >>>>
>> >>>> samples := flip <~ coin.
>> >>>>
>> >>>> This yields a new Bag with another 1000 samples.
>> >>>>
>> >>>>
>> >>>>
>> >>>> # Basic Concepts
>> >>>>
>> >>>> ## Reducing Functions
>> >>>>
>> >>>> A reducing function represents a single step in processing a data
>> >>>> sequence.
>> >>>> It takes an accumulated result and a value, and returns a new
>> >>>> accumulated
>> >>>> result.
>> >>>> For example:
>> >>>>
>> >>>> collect := [:col :e | col add: e; yourself].
>> >>>> sum := #+.
>> >>>>
>> >>>> A reducing function can also be ternary, i.e., it takes an
>> accumulated
>> >>>> result, a key and a value.
>> >>>> For example:
>> >>>>
>> >>>> collect := [:dic :k :v | dict at: k put: v; yourself].
>> >>>>
>> >>>> Reducing functions may be equipped with an optional completing
>> action.
>> >>>> After finishing processing, it is invoked exactly once, e.g., to
>> free
>> >>>> resources.
>> >>>>
>> >>>> stream := [:str :e | str nextPut: each; yourself] completing:
>> >>>> #close.
>> >>>> absSum := #+ completing: #abs
>> >>>>
>> >>>> A reducing function can end processing early by signaling Reduced
>> with a
>> >>>> result.
>> >>>> This mechanism also enables the treatment of infinite sources.
>> >>>>
>> >>>> nonNil := [:res :e | e ifNil: [Reduced signalWith: res]
>> ifFalse:
>> >>>> [res]].
>> >>>>
>> >>>> The primary approach to process a data sequence is the reducing
>> protocol
>> >>>> with the messages #reduce:init: and #transduce:reduce:init: if
>> >>>> transducers
>> >>>> are involved.
>> >>>> The behavior is similar to #inject:into: but in addition it takes
>> care
>> >>>> of:
>> >>>> - handling binary and ternary reducing functions,
>> >>>> - invoking the completing action after finishing, and
>> >>>> - stopping the reduction if Reduced is signaled.
>> >>>> The message #transduce:reduce:init: just combines the
>> transformation
>> and
>> >>>> the reducing step.
>> >>>>
>> >>>> However, as reducing functions are step-wise in nature, an
>> application
>> >>>> may
>> >>>> choose other means to process its data.
>> >>>>
>> >>>>
>> >>>> ## Reducibles
>> >>>>
>> >>>> A data source is called reducible if it implements the reducing
>> >>>> protocol.
>> >>>> Default implementations are provided for collections and streams.
>> >>>> Additionally, blocks without an argument are reducible, too.
>> >>>> This allows to adapt to custom data sources without additional
>> effort.
>> >>>> For example:
>> >>>>
>> >>>> "XStreams adaptor"
>> >>>> xstream := filename reading.
>> >>>> reducible := [[xstream get] on: Incomplete do: [Reduced
>> signal]].
>> >>>>
>> >>>> "natural numbers"
>> >>>> n := 0.
>> >>>> reducible := [n := n+1].
>> >>>>
>> >>>>
>> >>>> ## Transducers
>> >>>>
>> >>>> A transducer is an object that transforms a reducing function into
>> >>>> another.
>> >>>> Transducers encapsulate common steps in processing data sequences,
>> such
>> >>>> as
>> >>>> map, filter, concatenate, and flatten.
>> >>>> A transducer transforms a reducing function into another via
>> #transform:
>> >>>> in order to add those steps.
>> >>>> They can be composed using #* which yields a new transducer that
>> does
>> >>>> both
>> >>>> transformations.
>> >>>> Most transducers require an argument, typically blocks, symbols or
>> >>>> numbers:
>> >>>>
>> >>>> square := Map function: #squared.
>> >>>> take := Take number: 1000.
>> >>>>
>> >>>> To facilitate compact notation, the argument types implement
>> >>>> corresponding
>> >>>> methods:
>> >>>>
>> >>>> squareAndTake := #squared map * 1000 take.
>> >>>>
>> >>>> Transducers requiring no argument are singletons and can be
>> accessed
>> by
>> >>>> their class name.
>> >>>>
>> >>>> flattenAndDedupe := Flatten * Dedupe.
>> >>>>
>> >>>>
>> >>>>
>> >>>> # Advanced Concepts
>> >>>>
>> >>>> ## Data flows
>> >>>>
>> >>>> Processing a sequence of data can often be regarded as a data flow.
>> >>>> The operator #<~ allows define a flow from a data source through
>> >>>> processing steps to a drain.
>> >>>> For example:
>> >>>>
>> >>>> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
>> >>>> fileOut writeStream <~ #isSeparator filter <~ fileIn
>> readStream.
>> >>>>
>> >>>> In both examples #<~ is only used to set up the data flow using
>> reducing
>> >>>> functions and transducers.
>> >>>> In contrast to streams, transducers are completely independent from
>> >>>> input
>> >>>> and output sources.
>> >>>> Hence, we have a clear separation of reading data, writing data and
>> >>>> processing elements.
>> >>>> - Sources know how to iterate over data with a reducing function,
>> e.g.,
>> >>>> via #reduce:init:.
>> >>>> - Drains know how to collect data using a reducing function.
>> >>>> - Transducers know how to process single elements.
>> >>>>
>> >>>>
>> >>>> ## Reductions
>> >>>>
>> >>>> A reduction binds an initial value or a block yielding an initial
>> value
>> >>>> to
>> >>>> a reducing function.
>> >>>> The idea is to define a ready-to-use process that can be applied in
>> >>>> different contexts.
>> >>>> Reducibles handle reductions via #reduce: and #transduce:reduce:
>> >>>> For example:
>> >>>>
>> >>>> sum := #+ init: 0.
>> >>>> sum1 := #(1 1 1) reduce: sum.
>> >>>> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
>> >>>>
>> >>>> asSet := [:set :e | set add: e; yourself] initializer: [Set
>> new].
>> >>>> set1 := #(1 1 1) reduce: asSet.
>> >>>> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
>> >>>>
>> >>>> By combining a transducer with a reduction, a process can be
>> further
>> >>>> modified.
>> >>>>
>> >>>> sumOdds := sum <~ #odd filter
>> >>>> setOdds := asSet <~ #odd filter
>> >>>>
>> >>>>
>> >>>> ## Eductions
>> >>>>
>> >>>> An eduction combines a reducible data sources with a transducer.
>> >>>> The idea is to define a transformed (virtual) data source that
>> needs
>> not
>> >>>> to be stored in memory.
>> >>>>
>> >>>> odds1 := #odd filter <~ #(1 2 3) readStream.
>> >>>> odds2 := #odd filter <~ (1 to 1000).
>> >>>>
>> >>>> Depending on the underlying source, eductions can be processed once
>> >>>> (streams, e.g., odds1) or multiple times (collections, e.g.,
>> odds2).
>> >>>> Since no intermediate data is stored, transducers actions are lazy,
>> >>>> i.e.,
>> >>>> they are invoked each time the eduction is processed.
>> >>>>
>> >>>>
>> >>>>
>> >>>> # Origins
>> >>>>
>> >>>> Transducers is based on the same-named Clojure library and its
>> ideas.
>> >>>> Please see:
>> >>>> http://clojure.org/transducers
>> >>>>
>> >>>>
>> >
>>
>>
June 6, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Steffen Märcker
Hi!
>> If the need arises, we could of course factor the compact notation out
>> into
>> a separate package.
>Good idea
>[...] I do not want to help promoting a syntax that alienates me (and
> others because other people reported the saem to me).
I understand. Btw, I'd really, really appreciate if others post their
thoughts and feedback here as well. Discussion helps moving things
forward. =)
>> (collection transduce map: #squared) take: 1000.
>
> To me this is much more readable.
Well, I'll provide that extension once it is finished.
> I cannot and do not want to use the other forms.
>> collection transduce
>> map: #squared;
>> take: 1000.
>>
>> But as the message chain has to modify the underlying object
>> (an eduction), very snaky side effects my occur. E.g., consider
>>
>> eduction := collection transduce.
>> squared := eduction map: #squared.
>> take := squared take: 1000.
>>
>> Now, all three variables hold onto the same object, which first squares
>> all elements and than takes the first 1000.
>
> This is because the programmer did not understand what he did. No?
Sure. ;-) Nevertheless, it would be very hard to debug. All of which are
the reasons I wouldn't implement that variant. ;-)
> PS: I played with infinite stream and iteration back in 1993 in CLOS.
> Now I do not like to mix things because it breaks my flow of thinking.
I am not sure whether I understand what your mean by mixing. Concerning
transducers, the ability to handle infinite sources in only a (natural)
side-effect of the ability to finish reductions before all elements are
processed, e.g., like #detect: and such.
Best, Steffen
June 6, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Steffen Märcker
I assumed so. I used file-outs only to get something working quickly. =)
Properly published code will follow as soon as I am more familiar with
code management in Pharo.
Am .06.2017, 09:05 Uhr, schrieb Stephane Ducasse <stepharo.self(a)gmail.com>:
> We do not work with fileouts :)
> You should produce packages with also a configuration and published them
> on
> smalltalkhub or git and
> in the MetaRepository.
> You can also add package comments
>
> On Sat, Jun 3, 2017 at 10:29 PM, Steffen Märcker <merkste(a)web.de> wrote:
>
>> Dear all,
>>
>> attached are updated file-outs. I fixed a couple of annoyances that
>> slipped through yesterday evening. Most notable:
>>
>> 1) Random generator now works.
>> 2) Early termination via Reduced exception does MNU anymore.
>> 3) Printing a transducer holding a block does not MNU anymore.
>>
>> Please, give it a spin and tell me your impressions. (At least) The
>> coin-flipping the example from the package comment works now:
>>
>> scale := [:x | (x * 2 + 1) floor] map.
>> sides := #(heads tails) replace.
>> count := 1000 take.
>> collect := [:bag :c | bag add: c; yourself].
>> experiment := (scale * sides * count) transform: collect.
>> "experiment cannot be re-used"
>> samples := Random new
>> reduce: experiment
>> init: Bag new.
>> "transform and reduce in one step"
>> samples := Random new
>> transduce: scale * sides * count
>> reduce: collect
>> init: Bag new.
>> "assemble coin (eduction) and flip (reduction) objects"
>> coin := sides <~ scale <~ Random new.
>> flip := Bag <~ count.
>> "flip coin =)"
>> samples := flip <~ coin.
>>
>> Cheers!
>> Steffen
>>
>>
>>
>> Am .06.2017, 23:08 Uhr, schrieb Steffen Märcker <merkste(a)web.de>:
>>
>> Thanks, this appears to work. Attached you'll find the file-out from
>>> VisualWorks and the file-out from Pharo (includes package comment).
>>>
>>> Cheers!
>>> Steffen
>>>
>>>
>>> Am .06.2017, 20:06 Uhr, schrieb Yanni Chiu <yanni.code(a)gmail.com>:
>>>
>>> To get the extension methods into the Transducers package, the
>>> following
>>>> worked for me - edit the category to have the prefix '*Transducers-'
>>>>
>>>> 2710c2710
>>>>
>>>> < !Number methodsFor: 'transforming' stamp: ' 2/6/17 15:38'!
>>>>
>>>> ---
>>>>
>>>> !Number methodsFor: '*Transducers-transforming' stamp: ' 2/6/17
>>>> 15:38'!
>>>>>
>>>>
>>>>
>>>> On Fri, Jun 2, 2017 at 11:05 AM, Steffen Märcker <merkste(a)web.de>
>>>> wrote:
>>>>
>>>> Dear all,
>>>>>
>>>>> thanks for the many suggestions. I didn't had time to test all
>>>>> import/export ways yet. But for now, I can report on two:
>>>>>
>>>>> 1) NGFileOuter
>>>>> Unfortunately It raised several MNUs in my image. I'll investigate
>>>>> them
>>>>> later.
>>>>>
>>>>> 2) FileOut30 (VW Contributed)
>>>>> I was able to file out the code except for the package definition.
>>>>> Replacing {category: ''} in the class definitions with {package:
>>>>> 'Transducers'} fixed that. However, methods that extend existing
>>>>> classes
>>>>> did not end up in the Transducers package. Is there a similar easy
>>>>> change
>>>>> to the file-out making that happen? Also I'd like to add the package
>>>>> comment if that's possible.
>>>>>
>>>>> Most things appear to work as far as I can see. Two exceptions:
>>>>> 1) Random is a subclass of Stream in VW and in Pharo it is not.
>>>>> Hence,
>>>>> I'll have to copy some methods from Stream to Random.
>>>>> 2) I used #beImmutable in VW but I couldn't yet figure out how to
>>>>> make
>>>>> objects immutable in Pharo.
>>>>>
>>>>> However, until the tests are ported, I cannot guarantee. Porting the
>>>>> test
>>>>> suite will be another beast, since I rely on the excellent
>>>>> mocking/stubbing
>>>>> library DoubleAgents by Randy Coulman. I am not sure how I will
>>>>> handle
>>>>> that. In general, I think it would be really worth the effort to be
>>>>> ported
>>>>> to Pharo, too. DoubleAgents is pretty powerful and produces easy to
>>>>> read
>>>>> and understand mocking/stubbing code. Personally, I prefer it
>>>>> clearly,
>>>>> e.g., over Mocketry (no offence intended!).
>>>>>
>>>>> Attached you'll find the file-out that I loaded into Pharo. The
>>>>> issues
>>>>> above are not addressed yet. However, the following example works:
>>>>>
>>>>> | scale sides count collect experiment random samples coin flip |
>>>>> scale := [:x | (x * 2 + 1) floor] map.
>>>>> sides := #(heads tails) replace.
>>>>> count := 1000 take.
>>>>> collect := [:bag :c | bag add: c; yourself].
>>>>> experiment := (scale * sides * count) transform: collect.
>>>>> random := #(0.1 0.3 0.4 0.5 0.6 0.7 0.8 0.9).
>>>>>
>>>>> samples := random
>>>>> reduce: experiment
>>>>> init: Bag new.
>>>>>
>>>>> samples := random
>>>>> transduce: scale * sides * count
>>>>> reduce: collect
>>>>> init: Bag new.
>>>>>
>>>>> coin := sides <~ scale <~ random.
>>>>> flip := Bag <~ count.
>>>>>
>>>>> samples := flip <~ coin.
>>>>>
>>>>>
>>>>> Best, Steffen
>>>>>
>>>>>
>>>>>
>>>>> Am .06.2017, 08:16 Uhr, schrieb Stephane Ducasse
>>>>> <stepharo.self(a)gmail.com
>>>>> >:
>>>>>
>>>>> There is a package for that NGFileOuter or something like that on
>>>>> cincom
>>>>>
>>>>>> store.
>>>>>> We used it for mobydic code.
>>>>>>
>>>>>> On Wed, May 31, 2017 at 6:35 PM, Alexandre Bergel <
>>>>>> alexandre.bergel(a)me.com>
>>>>>> wrote:
>>>>>>
>>>>>> If I remember correctly, there is a parcel in VisualWorks to export
>>>>>> a
>>>>>> file
>>>>>>
>>>>>>> out (Squeak format).
>>>>>>>
>>>>>>> @Milton, can you give a hand to Steffen?
>>>>>>>
>>>>>>> Alexandre
>>>>>>> --
>>>>>>> _,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
>>>>>>> Alexandre Bergel http://www.bergel.eu
>>>>>>> ^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On May 31, 2017, at 10:32 AM, Steffen Märcker <merkste(a)web.de>
>>>>>>> wrote:
>>>>>>>
>>>>>>> Thanks for the encouraging response! First question: Which is the
>>>>>>> recommended (friction free) way to exchange code between VW and
>>>>>>> Pharo?
>>>>>>>
>>>>>>> Cheers!
>>>>>>> Steffen
>>>>>>>
>>>>>>> Am .05.2017, 16:22 Uhr, schrieb Alexandre Bergel <
>>>>>>> alexandre.bergel(a)me.com
>>>>>>> >:
>>>>>>>
>>>>>>> I second Sven. This is very exciting!
>>>>>>>
>>>>>>> Let us know when you have something ready to be tested.
>>>>>>>
>>>>>>> Alexandre
>>>>>>>
June 6, 2017
Re: [Pharo-users] Bloc/Brick/Spec
by Peter H. Meadows
What does 'Bloc Zeroconf Script' do?
What is the difference between the 4 different metacello lines here?
https://github.com/pharo-graphics/Brick
June 6, 2017
Re: [Pharo-users] Bloc/Brick/Spec
by Peter Uhnak
* Bloc - low level library (think basic shapes, rectangles, ...)
* Brick - widget library on top of Bloc akin to the widget part of Morphic (buttons, checkboxes, ...)
* Spec - UI framework with adaptable backend; currently using Morphic as a backend, however once Bloc/Brick matures, Bloc/Brick will be added as another backend (without affecting Spec users)
(and below Bloc is Sparta, which is a vector canvas)
Peter
On Mon, Jun 05, 2017 at 06:20:47PM -0700, Brad Selfridge wrote:
> I'm confused. I see the latest news and documentation about Bloc. Is Brick
> now dead and Bloc the default? I thought Brick was a layer on top of Bloc
> and Spec was layer on top on Brick? What is the direction now?
>
> Brad Selfridge
>
>
>
> -----
> Brad Selfridge
> --
> View this message in context: http://forum.world.st/Bloc-Brick-Spec-tp4949591.html
> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>
June 6, 2017
Slant question
by john pfersich
Slant has a question/poll out there
It's at https://www.slant.co/topics/25/~best-programming-language-to-learn-first?ut…
Let's pile on it!
Sent from my iPhone
June 6, 2017
Re: [Pharo-users] [Pharo-dev] GSoC Week 3 update - Enhancing Pharo Command Line
by Ben Coman
On Thu, Jun 1, 2017 at 5:06 PM, Rajula Vineet <Vineet.Reddy(a)iiitb.org>
wrote:
> Hi all,
>
> It has been about three weeks, I started working on my GSoC project. The
> first task I am working on is the new implementation for Current Working
> Directory. I have written the new implementation. Currently, I am testing
> the new code. Will soon share the work here.
> Meanwhile, for the week three, I have written a blog post
> <https://vineetreddy.wordpress.com/2017/05/29/cross-platform-with-pharo/>
> on OSPlatfrom. Please do take a look and give your feedback.
>
> Thanks,
> Rajula
>
>
>
Hi Rajula,
Great to see an article on this subject. Probably its at a good level for
pharo-users mail list as well, so I've copied there. Don't worry about the
limited response. Many in pharo-dev probably know this subject well. It
is still good to have it laid out like you did for newcomers to google when
they need to know.
cheers -ben
June 6, 2017
Bloc/Brick/Spec
by Brad Selfridge
I'm confused. I see the latest news and documentation about Bloc. Is Brick
now dead and Bloc the default? I thought Brick was a layer on top of Bloc
and Spec was layer on top on Brick? What is the direction now?
Brad Selfridge
-----
Brad Selfridge
--
View this message in context: http://forum.world.st/Bloc-Brick-Spec-tp4949591.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 6, 2017
Re: [Pharo-users] How to deploy headless app without changes and source files?
by Andreas Sunardi
I had my changes and sources files in the bundle but has their write
permission removed, and that causes the error. Simply deploying the tool
without the changes file seems to fix it. Pharo5 doesn't complain if the
changes file isn't there.
However, without the sources file, I get this warning that pharo cannot
locate the sources file. Including the sources file in the deployed tool is
fine with me.
So, I think that's my solution. Thanks!
On Mon, Jun 5, 2017 at 5:07 PM, Andreas Sunardi <a.sunardi(a)gmail.com> wrote:
> I found this StackOverflow question:
> https://stackoverflow.com/questions/14737695/is-it-
> possible-to-deploy-a-pharo-image-without-changes-and-
> sources-files/14747328
>
> and this older forum thread:
> https://www.mail-archive.com/pharo-project@lists.gforge.
> inria.fr/msg21170.html
>
> I'm using Pharo5.0 and neither of these options is available anymore. What
> is the new way to do this?
>
> --
> Andreas Sunardi
>
June 6, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Ben Coman
On Tue, Jun 6, 2017 at 5:11 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
wrote:
> Tx ben.
> When I see all this complexity for something that looks not that complex:
> I prefer to pass the class and get done.
> May be I missed something obvious... but when I see something too complex
> I start to get worried.
>
> I think that thinking about the contract between classes at runtime is
> important and to me a MovieLister should be using at runtime and instance
> of the *Finder*
> Now needing an extra class just to set this should really be evaluated
> with the tradeoff: "flexibility win" (our simple solution is still really
> flexible - I decide when I want to pass the correct finder) vs. the code
> and conceptual bloat.
>
>
> I'm happy not to face the hyper super over engineering of Java "solutions".
>
> I like the "Of course this just shifts the burden a tad, we still have to
> get the locator into the lister"
> but the solution is super simple let us use another "Singleton and a
> Factory...." :)
>
> Stef
>
> On Mon, Jun 5, 2017 at 8:43 PM, Ben Coman <btc(a)openinworld.com> wrote:
>
>>
>>
>> On Tue, Jun 6, 2017 at 1:26 AM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
>> wrote:
>>
>>> Thanks for the answer Ben and Stephane.
>>>
>>> I already read A Mentoring Course on Smalltalk, Valloud, there is
>>> nothing there I could use in this case :( . I will look after for The
>>> Design Patterns Smalltalk Companion. Most of the sources provided I already
>>> know of or went in the same lines lines of what I have already found.
>>>
>>> About TDD, I am experienced with the discipline and have tested it on
>>> Pharo living system already, but I could not understand how this is related
>>> with object wiring, DI and service locator.
>>>
>>
>> I guess I don't properly understand your need and those topics. That was
>> my quick pass. Now if I take the time to actually read Fowler's long
>> article
>>
>> "the inversion is about how they lookup a plugin implementation ... to
>> ensure that any user of a plugin follows some convention that allows a
>> separate assembler module to inject the implementation into the lister."
>>
>> "The basic idea of the Dependency Injection is to have a separate object,
>> an assembler, that populates a field in the lister class with an
>> appropriate implementation for the finder interface. There are three main
>> styles of dependency injection. The names I'm using for them are
>> Constructor Injection, Setter Injection, and Interface Injection."
>>
>> Now there was too much syntactical noise in those Java examples for me to
>> think clearly, so I converted them all to Smalltalk.
>>
>>
>> ##CONSTRUCTOR INJECTION
>>
>> Object subclass: MovieLister
>> instanceVariables: 'finder'
>>
>>
>> MovieLister class >> newWith: aFinder
>> ^ self basicNew initializeWith: aFinder
>>
>> MovieLister >> initializeWith: aFinder
>> finder := aFinder
>>
>>
>> ColonMovieFinder class >> newWith: aFilename
>> ^ self basicNew initializeWith: aFilename
>>
>> ColonMovieFinder >> initializeWith: aFilename
>> filename := aFilename.
>>
>>
>> ConstructorInjectionContainer >> new
>> container := DefaultContainer new. "the article doesn't specify
>> where this comes from"
>> finderParams := ConstantParameter newWith: 'movies1.txt'.
>> container registerComponentInterface: MovieFinderInterface
>> implementation: ColonMovieFinder
>> params: finderParams.
>> container registerComponentImplementation: MovieLister
>> ^container
>>
>> to be used like this...
>> ConstructorInjectionTest >> testWithContainer
>> container := ConstructorInjectionContainer new.
>> lister := container getComponentInstance( MovieLister ).
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>> The article poorly defines registerComponentXXX: or getComponentInstance:
>> methods, so I don't dwell on them. I presume its little relevant to the
>> main theme.
>>
>>
>> ##SETTER INJECTION
>>
>> MovieLister >> setFinder: aFinder
>> finder := aFinder.
>>
>> ColonMovieFinder >> setFilename: aFilename
>> filename := aFilename.
>>
>> SetterInjectionTest >> testWithConfigurationFile
>> ctx := SomeXmlApplicationConfiguration on: 'config.xml'.
>> lister := ctx getConfigOf: 'MovieLister'.
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>>
>> ##INTERFACE INJECTION
>>
>> MovieLister >> injectFinder: aFinder
>> finder := aFinder
>>
>> ColonMovieFinder >> injectFilename: aFilename
>> filename := aFilename
>>
>> InterfaceInjectionTest >> configureContainer
>> container := InterfaceInjectionContainer new.
>> self registerComponents.
>> self registerInjectors.
>> container start.
>>
>> InterfaceInjectionTest >> registerComponents
>> container registerComponent: 'MovieLister' with: MovieLister.
>> container registerComponent: 'MovieFinder' with: ColonMovieFinder.
>>
>> InterfaceInjectionTest >> registerInjectors
>> container registerInjector: Injector with: (container lookup:
>> 'MovieFinder').
>> container registerInjector: InjectorFinderFilename with:
>> FinderFilenameInjector new.
>>
>> ColonMovieFinder >> inject: anObject
>> anObject injectFinder: self.
>>
>> FinderFilenameInjector >> inject: anObject
>> anObject injectFilename: 'movies1.txt'.
>>
>> InterfaceInjectionTester >> testInterface
>> self configureContainer.
>> lister := container lookup: 'MovieLister'.
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>> The article doesn't define InterfaceInjectionContainer, but I guess it
>> could look like this...
>>
>> InterfaceInjectionContainer >> registerComponent: componentName with:
>> aComponent
>> container ifNil: [ container := Dictionary new].
>> container at: componentName put: aComponent
>>
>> InterfaceInjectionContainer >> lookup: componentName
>> ^ container at: componentName
>>
>>
>> ##SERVICE LOCATOR
>>
>> "The basic idea behind a service locator is to have an object that knows
>> how to get hold of all of the services that an application might need. So a
>> service locator for this application would have a method that returns a
>> movie finder when one is needed. Of course this just shifts the burden a
>> tad, we still have to get the locator into the lister"
>>
>> MovieLister >> initialize
>> finder := ServiceLocator movieFinder.
>>
>>
>> Object subclass: ServiceLocator
>> instanceVariable: 'movieFinder'
>> classVariable: 'SoleInstance'
>>
>> ServiceLocator class >> load: aServiceLocator
>> SoleInstance := aServiceLocator
>>
>> ServiceLocator class >> soleInstance
>> ^ SoleInstance
>>
>> ServiceLocator class >> movieFinder
>> ^ self soleInstance movieFinder
>>
>> ServiceLocator >> movieFinder
>> ^movieFinder
>>
>>
>> ServiceLocatorTest >> configure
>> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
>> newWith: 'movies1.txt'))
>>
>>
>> ServiceLocator class >> newWith: aMovieFinder
>> ^ self basicNew initializeWithFinder: aMovieFinder
>>
>> ServiceLocator >> initializeWithFinder: aMovieFinder
>> movieFinder := aMovieFinder
>>
>>
>> ServiceLocatorTest >> testSimple
>> self configure.
>> lister := MovieLister new.
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>> So it seems that a service locator is just a Singleton pattern having a
>> class variable for each service of interest ??
>>
>
It was late and I mispoke here, of course this should have said...
* a Singleton pattern having an instance variable for each service of
interest
* a Singleton pattern having a getter method (with hidden implementation) for
each service of interest
> So in good faith** I ask... "Is it any more complicated than that?"
>>
>> **Since its taken me a couple of hours to convert the Java to this point
>> so I stopped reading to seek your feedback.
>>
>
but I'll add, it was so much simpler to understand without all that Java
typing boiler plate.
cheers -ben
> Is that enough insight to adapt to your needs, or is there something else
>> further down the article that invalidates my analysis?
>>
>>
>>
>>
>>
>>>
>>> From ben:
>>>
>>> "I'm not really familiar with IoC or DI patterns, so just taking your
>>>> example at face value, in Pharo I'd do...
>>>>
>>>> MovieLister>>moviesDirectedBy: director
>>>> allMovies := finder allMovies.
>>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>>> "although typically #getDirector would be renamed #director"
>>>>
>>>> MovieLister>>finder: movieFinder
>>>> finder := movieFinder.
>>>>
>>>> to be used like this...
>>>> lister := MovieLister new finder: (ColonDelimitedMovieFinder on:
>>>> 'movies1.txt').
>>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>>
>>>
>>
>> So per Fowler, the above is equivalent to "Setter Injection with Spring"
>>
>>
>>>
>>> and Stephane:
>>>
>>> Why don't you simply pass the class and use that class in your
>>>> MovieLister?
>>>>
>>>> MovieLister new
>>>> finderClass: MySuperCoolFinderClass
>>>>
>>>> ...
>>>> MovieLister finder
>>>> finderClass new .....
>>>>
>>>> What is wrong with that.
>>>
>>>
>>> That was what I meant when I said: "I know that in Smalltalk I can make
>>> MovieLister to receive, upon construction, a class representing MovieFinder
>>> and call it construction message.". The code I had in mind is a bit of
>>> mix from the one provided by you both:
>>>
>>> MovieLister>>moviesDirectedBy: director
>>> allMovies := finder allMovies.
>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>> "although typically #getDirector would be renamed #director"
>>>
>>> MovieLister>>finder: aMovieFinderBuilder
>>> finder := aMovieFinderClass new.
>>>
>>> to be used like this...
>>> lister := MovieLister new finder: (ColonDelimitedMovieFinder
>>> builderOn: 'movies1.txt').
>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>>
>>> But that means I will have to wire dependencies by hand whenever I
>>> create a MovieLister and seek through code when and if those dependencies
>>> change. When there are lot's of dependencies it's is a considerable and
>>> tedious work. Let's see an image from Fowlers article:
>>>
>>> [image: Inline image 1]
>>>
>>> In this case, the service locator provides me with an instance and I
>>> configure the instance in the assembler, the scheme is alike for an IoC,
>>> and that would mean my implementation could be like this:
>>>
>>>
>>> MovieLister>>moviesDirectedBy: director
>>> allMovies := finder allMovies.
>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>> "although typically #getDirector would be renamed #director"
>>>
>>> MovieLister>>initialize
>>> finder := ServiceLocator locate: FinderClass <--- This would
>>> bring the instance of finder class configured by the assembler
>>>
>>
>> No, like this...
>> finder := ServiceLocation movieFinder.
>>
>> Now if you want to store a class rather than an instance as I did higher
>> up, you just do this...
>>
>> Object subclass: ServiceLocator
>> instanceVariable: 'movieFinderClass'
>> classVariable: 'SoleInstance'
>>
>> ServiceLocator class >> movieFinder
>> ^ self soleInstance movieFinderClass new
>>
>>
>>
>>>
>>>
>>> to be used like this...
>>> lister := MovieLister new.
>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>>
>>> and the assembler:
>>>
>>> Assember class>>configure:
>>> aMap put: (ColonDelimitedMovieFinder builderOn: 'movies1.txt') at:
>>> FinderClass
>>>
>>
>> Assembler class>>configure
>> ServiceLocator load:
>> (ServiceLocator new
>> movieFinder: (ColonMovieFinder newWith: 'movies1.txt')
>> otherService: MyCustomService new)
>>
>>
>>>
>>> My assembler and service locator could be even more elaborated, and
>>> provide a different MovieFinder in test scope, for different classes or
>>> wharever.
>>>
>>
>> Really, the test should not be updating the class variable global like
>> this...
>> ServiceLocatorTest >> configure
>> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
>> newWith: 'movies1.txt'))
>>
>> you probably want something like (its rough but shows the point...)
>> Object subclass: #MovieLister
>> instanceVariables: 'serviceLocator'
>>
>> MovieLister >> initialize
>> serviceLocator ifNil: [ serviceLocator := ServiceLocator soleInstance
>> ].
>> finder := serviceLocator movieFinder.
>>
>> MovieLister class >> newWithServiceLocator: aServiceLocator
>> ^ (self basicNew initializeWithServiceLocator: aServiceLocator)
>> initialize.
>>
>> MovieLister >> initializeWithServiceLocator: aServiceLocator
>> serviceLocator := aServiceLocator
>>
>> ServiceLocatorTest >> testSimple2
>> lister := MovieLister newWithServiceLocator: (ServiceLocator newWith:
>> (ColonMovieFinder newWith: 'movies1.txt')).
>> movies = lister moviesDirectedBy: 'Sergio Leone'.
>> self assert: (movies includes: 'Once Upon a Time in the West')
>>
>>
>> cheers -ben
>>
>>
>>>
>>> It is a little convenience for Smalltalk, I will give that, but I was
>>> wandering if there was something alike in Pharo, by your answers I assuming
>>> there is nothing like that.
>>>
>>>
>>>
>>> On Mon, Jun 5, 2017 at 6:41 AM, Stephane Ducasse <
>>> stepharo.self(a)gmail.com> wrote:
>>>
>>>> Why don't you simply pass the class and use that class in your
>>>> MovieLister?
>>>>
>>>> MovieLister new
>>>> finderClass: MySuperCoolFinderClass
>>>>
>>>> ...
>>>> MovieLister finder
>>>> finderClass new .....
>>>>
>>>> What is wrong with that.
>>>>
>>>> If you do not want to have a reference at runtime to a Finder then you
>>>> need to use announcement and registration.
>>>>
>>>> Stef
>>>>
>>>>
>>>>
>>>> On Sun, Jun 4, 2017 at 11:17 PM, Vitor Medina Cruz <
>>>> vitormcruz(a)gmail.com> wrote:
>>>> > Hello,
>>>> >
>>>> > I would like to know how people in Pharo ecosystem do to deal with
>>>> object
>>>> > wiring, as described by Marting Fowler in
>>>> > https://martinfowler.com/articles/injection.html#FormsOfDepe
>>>> ndencyInjection:
>>>> >
>>>> > "A common issue to deal with is how to wire together different
>>>> elements: how
>>>> > do you fit together this web controller architecture with that
>>>> database
>>>> > interface backing when they were built by different teams with little
>>>> > knowledge of each other."
>>>> >
>>>> > He gives an example, I will leave it in java as it is simple enough to
>>>> > understand:
>>>> >
>>>> > "class MovieLister...
>>>> >
>>>> > public Movie[] moviesDirectedBy(String arg) {
>>>> > List allMovies = finder.findAll();
>>>> > for (Iterator it = allMovies.iterator(); it.hasNext();) {
>>>> > Movie movie = (Movie) it.next();
>>>> > if (!movie.getDirector().equals(arg)) it.remove();
>>>> > }
>>>> > return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
>>>> >
>>>> > }"
>>>> >
>>>> > The question is how to provide the finder object in a decoupled
>>>> matter, a
>>>> > naive approach would be:
>>>> >
>>>> > " private MovieFinder finder;
>>>> >
>>>> > public MovieLister() {
>>>> > finder = new ColonDelimitedMovieFinder("movies1.txt");
>>>> >
>>>> > }"
>>>> >
>>>> > Which couples the MovieLister to the specific
>>>> ColonDelimitedMovieFinder
>>>> > class.
>>>> >
>>>> > Fowler explains how to decouple using an IoC framework or a Service
>>>> Locator.
>>>> > In Java and .Net IoC is used most of the time. I Googled how this
>>>> problem is
>>>> > approached in Smalltalk/Pharo, and I generally I found answers "that
>>>> is easy
>>>> > to do in Smalltalk, so there is no need of a framework", what I miss
>>>> is a
>>>> > description on *how* to do that:
>>>> >
>>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>>> > https://stackoverflow.com/questions/2684326/is-there-a-depen
>>>> dency-injection-framework-for-smalltalk
>>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>>> /347477#347477
>>>> >
>>>> > I know that in Smalltalk I can make MovieLister to receive, upon
>>>> > construction, a class representing MovieFinder and call it
>>>> construction
>>>> > message. As long an object that responds to this message is provided,
>>>> I can
>>>> > create as many derivations I want and the MovieLister will be
>>>> decoupled from
>>>> > the MovieFinder. That way, however, I still have to wire things by
>>>> hand, and
>>>> > I am not sure if this is what I am supposed to do in order to solve
>>>> the
>>>> > decouple problem.
>>>> >
>>>> > Can you explain me how this is done in Pharo? It's is usually wiring
>>>> by
>>>> > hand? Is there a simple construction that deals with the wiring
>>>> problem that
>>>> > I cannot foresee?
>>>> >
>>>> > Thanks in advance,
>>>> > Vitor
>>>> >
>>>> >
>>>> >
>>>>
>>>>
>>>
>>
>
June 6, 2017
How to deploy headless app without changes and source files?
by Andreas Sunardi
I found this StackOverflow question:
https://stackoverflow.com/questions/14737695/is-it-possible-to-deploy-a-pha…
and this older forum thread:
https://www.mail-archive.com/pharo-project@lists.gforge.inria.fr/msg21170.h…
I'm using Pharo5.0 and neither of these options is available anymore. What
is the new way to do this?
--
Andreas Sunardi
June 6, 2017
Re: [Pharo-users] Saving selected changes in Monticello
by Andreas Sunardi
I definitely will check Komitter and I can use and fallback to Ben's
method. Thank you to all of you.
On Mon, Jun 5, 2017 at 12:58 AM, Peter Uhnak <i.uhnak(a)gmail.com> wrote:
> Komitter could indeed help you, see https://www.peteruhnak.com/
> blog/2016/08/12/fine-grained-committing-and-extending-nautilus/
>
> Peter
>
> On Mon, Jun 05, 2017 at 08:27:23AM +0200, serge.stinckwich(a)gmail.com
> wrote:
> > Kommiter available in default image allows you do cherry pick quite
> easily.
> >
> > Envoyé de mon iPhone
> >
> > > Le 5 juin 2017 à 07:14, Ben Coman <btc(a)openinworld.com> a écrit :
> > >
> > >
> > >
> > >> On Mon, Jun 5, 2017 at 10:12 AM, Andreas Sunardi <a.sunardi(a)gmail.com>
> wrote:
> > >> I have a half done changes in my image, but I need to distribute the
> other changes that are done. I thought I was going to do this all at once,
> but now I realize I should split this into 2 commit versions.
> > >>
> > >> Is there a way in Monticello to say save my changes, but not this and
> that changes? I can't seem to find it nor in books. How do people deal with
> this situation?
> > >
> > > AFAIK, Monticello cannot cherry pick. One work around is probably
> something like...
> > > 1. Save the mcz locally
> > > 2. Merge back into a fresh image selecting only the bits you want.
> > > 3. Save as a second mcz.
> > > One issue is that the second mcz will have the first mcz as an
> ancestor, so before 2 you might create a new changeset to file out after 2,
> and load that into a second new image. yuck!
> > >
> > > Another alternative might be to use Tools > ChangeSorter to move the
> code you want to exclude from the mcz to a changeset, file that out and
> then revert that code in the image. After save the package to a mcz, reload
> the changeset.
> > >
> > > cheers -ben
>
>
June 5, 2017
Re: [Pharo-users] STON Question
by Offray Vladimir Luna Cárdenas
Ok Stef. Happy that we're exploring different paths ;-).
Cheers,
Offray
On 05/06/17 13:56, Stephane Ducasse wrote:
> Hi offray
>
> Thanks but pillar ha a conf since several years and it is working
> well. Now I'm revisiting the implementation of cocoon
> because I want to have it simpler independent of magritte and better
> tested.
>
> Now I just want to add a new functionality to output a configuration
> file from the
> objects and in Pillar the configuration objects hold more complex
> ***objects***.
> So just taking the object and turning it in ston does not work.
>
> Stef
>
> On Mon, Jun 5, 2017 at 6:23 PM, Offray Vladimir Luna Cárdenas
> <offray.luna(a)mutabit.com <mailto:offray.luna@mutabit.com>> wrote:
>
> Hi,
>
> Maybe what I'm doing in Grafoscopio could help.
>
> I have a %metadata node which contains all configuration options
> for the production of the document (as shown in the image below).
> Exporting a document consist in looking for these nodes while
> traversing the notebook tree and applying that options in the
> proper place. You can see the source code of the current notebook
> STON file at [1], the exported markdown file at [2] and the
> exported PDF at [3]. As you can see I have pretty good control of
> the configuration of the document using this option (and a single
> place to manage all, without endless small files and folders for a
> document, but event that exporting options as split folders and
> docs, could be added also).
>
> [1]
> http://mutabit.com/repos.fossil/grafoscopio/artifact/fb25442038a0d4a1
> <http://mutabit.com/repos.fossil/grafoscopio/artifact/fb25442038a0d4a1>
> [2]
> http://mutabit.com/repos.fossil/grafoscopio/artifact?name=59245142cf93590b&…
> <http://mutabit.com/repos.fossil/grafoscopio/artifact?name=59245142cf93590b&…>
> [3]
> http://mutabit.com/repos.fossil/grafoscopio/doc/tip/Docs/En/Books/Manual/ma…
> <http://mutabit.com/repos.fossil/grafoscopio/doc/tip/Docs/En/Books/Manual/ma…>
>
>
>
> Cheers,
>
> Offray
>
>
> On 05/06/17 01:58, Stephane Ducasse wrote:
>> Sven I know what Ston is :)
>>
>> Now Pillar dev used Ston as input and it works. Then with some
>> hooks they let the user convert the strings
>> into specific objects and this is ok.
>> Now I want to add export in Ston and for configurations I need to
>> control for the application and not as a ston object the value saved.
>> For example a file reference should not be just a file reference
>> in Ston but
>> a string relative the the baseDirectory of the configuration.
>>
>> So I thought that I can build a hook and control the call to Ston
>> (convert the object before to the correct values) and export.
>> It should be working now doing this I found myself redoing the
>> output of Ston.
>> So I will do it. Then I thought that may be I could reuse this
>> logic.
>>
>> Stef
>>
>>
>>
>> On Sun, Jun 4, 2017 at 11:49 PM, Sven Van Caekenberghe
>> <sven(a)stfx.eu <mailto:sven@stfx.eu>> wrote:
>>
>> Stef,
>>
>> STON is like FUEL, it can write any object to a stream and
>> read it back. Although you can customise how this is done,
>> only one way of doing so is supported (i.e. you cannot change
>> the format for each application).
>>
>> People have used STON for various applications now, including
>> for configuration stuff (because it is a textual format that
>> is easy to read).
>>
>> I would suggest you just try to see what your config looks
>> like once you have the objects in Pharo.
>>
>> STON toStringPretty: myConfig.
>>
>> Then we can see how to tune the representation.
>>
>> Sven
>>
>> > On 4 Jun 2017, at 22:58, Stephane Ducasse
>> <stepharo.self(a)gmail.com <mailto:stepharo.self@gmail.com>> wrote:
>> >
>> > Hi sven
>> >
>> > I'm working on a new configuration frameworks similar to
>> the one use pillar.conf.
>> >
>> > So basically I have
>> >
>> > ston := '{
>> > "newLine":#unix,
>> > "separateOutputFiles":true
>> > }'.
>> > and I want to recreate it.
>> >
>> > So I did
>> >
>> > Object >> toConfigurationString
>> >
>> > ^ STON toString: self
>> >
>> > SimpleConfiguration >> exportStream
>> >
>> > ^ String streamContents: [ :str |
>> > str << '{' .
>> > self propertiesKeysAndValuesDo: [ :key :value|
>> > str << key toConfigurationString.
>> > str << ':'.
>> > str << value toConfigurationString.
>> > str << ','.
>> > str lf.
>> > ].
>> > str << '}'.
>> > str contents
>> > ]
>> >
>> > The idea is that for special configuration values people
>> should be able to define
>> > how to go from the object to configuration.
>> > For example for some FileReference I want to have just the
>> path up to the baseDirectory.
>> >
>> > Now I wonder if I could not better reuse ston.
>> > I saw the stonOn:
>> > but I did not look further because I was wondering how the
>> writer where passed.
>> >
>> > Any feedback is welcome.
>> >
>> > Stef (now bed time).
>> >
>>
>>
>>
>
>
June 5, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Stephane Ducasse
Tx ben.
When I see all this complexity for something that looks not that complex: I
prefer to pass the class and get done.
May be I missed something obvious... but when I see something too complex I
start to get worried.
I think that thinking about the contract between classes at runtime is
important and to me a MovieLister should be using at runtime and instance
of the *Finder*
Now needing an extra class just to set this should really be evaluated with
the tradeoff: "flexibility win" (our simple solution is still really
flexible - I decide when I want to pass the correct finder) vs. the code
and conceptual bloat.
I'm happy not to face the hyper super over engineering of Java "solutions".
I like the "Of course this just shifts the burden a tad, we still have to
get the locator into the lister"
but the solution is super simple let us use another "Singleton and a
Factory...." :)
Stef
On Mon, Jun 5, 2017 at 8:43 PM, Ben Coman <btc(a)openinworld.com> wrote:
>
>
> On Tue, Jun 6, 2017 at 1:26 AM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
> wrote:
>
>> Thanks for the answer Ben and Stephane.
>>
>> I already read A Mentoring Course on Smalltalk, Valloud, there is
>> nothing there I could use in this case :( . I will look after for The
>> Design Patterns Smalltalk Companion. Most of the sources provided I already
>> know of or went in the same lines lines of what I have already found.
>>
>> About TDD, I am experienced with the discipline and have tested it on
>> Pharo living system already, but I could not understand how this is related
>> with object wiring, DI and service locator.
>>
>
> I guess I don't properly understand your need and those topics. That was
> my quick pass. Now if I take the time to actually read Fowler's long
> article
>
> "the inversion is about how they lookup a plugin implementation ... to
> ensure that any user of a plugin follows some convention that allows a
> separate assembler module to inject the implementation into the lister."
>
> "The basic idea of the Dependency Injection is to have a separate object,
> an assembler, that populates a field in the lister class with an
> appropriate implementation for the finder interface. There are three main
> styles of dependency injection. The names I'm using for them are
> Constructor Injection, Setter Injection, and Interface Injection."
>
> Now there was too much syntactical noise in those Java examples for me to
> think clearly, so I converted them all to Smalltalk.
>
>
> ##CONSTRUCTOR INJECTION
>
> Object subclass: MovieLister
> instanceVariables: 'finder'
>
>
> MovieLister class >> newWith: aFinder
> ^ self basicNew initializeWith: aFinder
>
> MovieLister >> initializeWith: aFinder
> finder := aFinder
>
>
> ColonMovieFinder class >> newWith: aFilename
> ^ self basicNew initializeWith: aFilename
>
> ColonMovieFinder >> initializeWith: aFilename
> filename := aFilename.
>
>
> ConstructorInjectionContainer >> new
> container := DefaultContainer new. "the article doesn't specify where
> this comes from"
> finderParams := ConstantParameter newWith: 'movies1.txt'.
> container registerComponentInterface: MovieFinderInterface
> implementation: ColonMovieFinder
> params: finderParams.
> container registerComponentImplementation: MovieLister
> ^container
>
> to be used like this...
> ConstructorInjectionTest >> testWithContainer
> container := ConstructorInjectionContainer new.
> lister := container getComponentInstance( MovieLister ).
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
> The article poorly defines registerComponentXXX: or getComponentInstance:
> methods, so I don't dwell on them. I presume its little relevant to the
> main theme.
>
>
> ##SETTER INJECTION
>
> MovieLister >> setFinder: aFinder
> finder := aFinder.
>
> ColonMovieFinder >> setFilename: aFilename
> filename := aFilename.
>
> SetterInjectionTest >> testWithConfigurationFile
> ctx := SomeXmlApplicationConfiguration on: 'config.xml'.
> lister := ctx getConfigOf: 'MovieLister'.
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
>
> ##INTERFACE INJECTION
>
> MovieLister >> injectFinder: aFinder
> finder := aFinder
>
> ColonMovieFinder >> injectFilename: aFilename
> filename := aFilename
>
> InterfaceInjectionTest >> configureContainer
> container := InterfaceInjectionContainer new.
> self registerComponents.
> self registerInjectors.
> container start.
>
> InterfaceInjectionTest >> registerComponents
> container registerComponent: 'MovieLister' with: MovieLister.
> container registerComponent: 'MovieFinder' with: ColonMovieFinder.
>
> InterfaceInjectionTest >> registerInjectors
> container registerInjector: Injector with: (container lookup:
> 'MovieFinder').
> container registerInjector: InjectorFinderFilename with:
> FinderFilenameInjector new.
>
> ColonMovieFinder >> inject: anObject
> anObject injectFinder: self.
>
> FinderFilenameInjector >> inject: anObject
> anObject injectFilename: 'movies1.txt'.
>
> InterfaceInjectionTester >> testInterface
> self configureContainer.
> lister := container lookup: 'MovieLister'.
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
> The article doesn't define InterfaceInjectionContainer, but I guess it
> could look like this...
>
> InterfaceInjectionContainer >> registerComponent: componentName with:
> aComponent
> container ifNil: [ container := Dictionary new].
> container at: componentName put: aComponent
>
> InterfaceInjectionContainer >> lookup: componentName
> ^ container at: componentName
>
>
> ##SERVICE LOCATOR
>
> "The basic idea behind a service locator is to have an object that knows
> how to get hold of all of the services that an application might need. So a
> service locator for this application would have a method that returns a
> movie finder when one is needed. Of course this just shifts the burden a
> tad, we still have to get the locator into the lister"
>
> MovieLister >> initialize
> finder := ServiceLocator movieFinder.
>
>
> Object subclass: ServiceLocator
> instanceVariable: 'movieFinder'
> classVariable: 'SoleInstance'
>
> ServiceLocator class >> load: aServiceLocator
> SoleInstance := aServiceLocator
>
> ServiceLocator class >> soleInstance
> ^ SoleInstance
>
> ServiceLocator class >> movieFinder
> ^ self soleInstance movieFinder
>
> ServiceLocator >> movieFinder
> ^movieFinder
>
>
> ServiceLocatorTest >> configure
> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
> newWith: 'movies1.txt'))
>
>
> ServiceLocator class >> newWith: aMovieFinder
> ^ self basicNew initializeWithFinder: aMovieFinder
>
> ServiceLocator >> initializeWithFinder: aMovieFinder
> movieFinder := aMovieFinder
>
>
> ServiceLocatorTest >> testSimple
> self configure.
> lister := MovieLister new.
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
> So it seems that a service locator is just a Singleton pattern having a
> class variable for each service of interest ??
> So in good faith** I ask... "Is it any more complicated than that?"
>
> **Since its taken me a couple of hours to convert the Java to this point
> so I stopped reading to seek your feedback.
> Is that enough insight to adapt to your needs, or is there something else
> further down the article that invalidates my analysis?
>
>
>
>
>
>>
>> From ben:
>>
>> "I'm not really familiar with IoC or DI patterns, so just taking your
>>> example at face value, in Pharo I'd do...
>>>
>>> MovieLister>>moviesDirectedBy: director
>>> allMovies := finder allMovies.
>>> ^ allMovies select: [ :movie | movie getDirector = director ].
>>> "although typically #getDirector would be renamed #director"
>>>
>>> MovieLister>>finder: movieFinder
>>> finder := movieFinder.
>>>
>>> to be used like this...
>>> lister := MovieLister new finder: (ColonDelimitedMovieFinder on:
>>> 'movies1.txt').
>>> movies := lister moviesDirectedBy: 'Tarantino'."
>>
>>
>
> So per Fowler, the above is equivalent to "Setter Injection with Spring"
>
>
>>
>> and Stephane:
>>
>> Why don't you simply pass the class and use that class in your
>>> MovieLister?
>>>
>>> MovieLister new
>>> finderClass: MySuperCoolFinderClass
>>>
>>> ...
>>> MovieLister finder
>>> finderClass new .....
>>>
>>> What is wrong with that.
>>
>>
>> That was what I meant when I said: "I know that in Smalltalk I can make
>> MovieLister to receive, upon construction, a class representing MovieFinder
>> and call it construction message.". The code I had in mind is a bit of
>> mix from the one provided by you both:
>>
>> MovieLister>>moviesDirectedBy: director
>> allMovies := finder allMovies.
>> ^ allMovies select: [ :movie | movie getDirector = director ].
>> "although typically #getDirector would be renamed #director"
>>
>> MovieLister>>finder: aMovieFinderBuilder
>> finder := aMovieFinderClass new.
>>
>> to be used like this...
>> lister := MovieLister new finder: (ColonDelimitedMovieFinder
>> builderOn: 'movies1.txt').
>> movies := lister moviesDirectedBy: 'Tarantino'."
>>
>> But that means I will have to wire dependencies by hand whenever I create
>> a MovieLister and seek through code when and if those dependencies change.
>> When there are lot's of dependencies it's is a considerable and tedious
>> work. Let's see an image from Fowlers article:
>>
>> [image: Inline image 1]
>>
>> In this case, the service locator provides me with an instance and I
>> configure the instance in the assembler, the scheme is alike for an IoC,
>> and that would mean my implementation could be like this:
>>
>>
>> MovieLister>>moviesDirectedBy: director
>> allMovies := finder allMovies.
>> ^ allMovies select: [ :movie | movie getDirector = director ].
>> "although typically #getDirector would be renamed #director"
>>
>> MovieLister>>initialize
>> finder := ServiceLocator locate: FinderClass <--- This would bring
>> the instance of finder class configured by the assembler
>>
>
> No, like this...
> finder := ServiceLocation movieFinder.
>
> Now if you want to store a class rather than an instance as I did higher
> up, you just do this...
>
> Object subclass: ServiceLocator
> instanceVariable: 'movieFinderClass'
> classVariable: 'SoleInstance'
>
> ServiceLocator class >> movieFinder
> ^ self soleInstance movieFinderClass new
>
>
>
>>
>>
>> to be used like this...
>> lister := MovieLister new.
>> movies := lister moviesDirectedBy: 'Tarantino'."
>>
>> and the assembler:
>>
>> Assember class>>configure:
>> aMap put: (ColonDelimitedMovieFinder builderOn: 'movies1.txt') at:
>> FinderClass
>>
>
> Assembler class>>configure
> ServiceLocator load:
> (ServiceLocator new
> movieFinder: (ColonMovieFinder newWith: 'movies1.txt')
> otherService: MyCustomService new)
>
>
>>
>> My assembler and service locator could be even more elaborated, and
>> provide a different MovieFinder in test scope, for different classes or
>> wharever.
>>
>
> Really, the test should not be updating the class variable global like
> this...
> ServiceLocatorTest >> configure
> ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
> newWith: 'movies1.txt'))
>
> you probably want something like (its rough but shows the point...)
> Object subclass: #MovieLister
> instanceVariables: 'serviceLocator'
>
> MovieLister >> initialize
> serviceLocator ifNil: [ serviceLocator := ServiceLocator soleInstance
> ].
> finder := serviceLocator movieFinder.
>
> MovieLister class >> newWithServiceLocator: aServiceLocator
> ^ (self basicNew initializeWithServiceLocator: aServiceLocator)
> initialize.
>
> MovieLister >> initializeWithServiceLocator: aServiceLocator
> serviceLocator := aServiceLocator
>
> ServiceLocatorTest >> testSimple2
> lister := MovieLister newWithServiceLocator: (ServiceLocator newWith:
> (ColonMovieFinder newWith: 'movies1.txt')).
> movies = lister moviesDirectedBy: 'Sergio Leone'.
> self assert: (movies includes: 'Once Upon a Time in the West')
>
>
> cheers -ben
>
>
>>
>> It is a little convenience for Smalltalk, I will give that, but I was
>> wandering if there was something alike in Pharo, by your answers I assuming
>> there is nothing like that.
>>
>>
>>
>> On Mon, Jun 5, 2017 at 6:41 AM, Stephane Ducasse <stepharo.self(a)gmail.com
>> > wrote:
>>
>>> Why don't you simply pass the class and use that class in your
>>> MovieLister?
>>>
>>> MovieLister new
>>> finderClass: MySuperCoolFinderClass
>>>
>>> ...
>>> MovieLister finder
>>> finderClass new .....
>>>
>>> What is wrong with that.
>>>
>>> If you do not want to have a reference at runtime to a Finder then you
>>> need to use announcement and registration.
>>>
>>> Stef
>>>
>>>
>>>
>>> On Sun, Jun 4, 2017 at 11:17 PM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
>>> wrote:
>>> > Hello,
>>> >
>>> > I would like to know how people in Pharo ecosystem do to deal with
>>> object
>>> > wiring, as described by Marting Fowler in
>>> > https://martinfowler.com/articles/injection.html#FormsOfDepe
>>> ndencyInjection:
>>> >
>>> > "A common issue to deal with is how to wire together different
>>> elements: how
>>> > do you fit together this web controller architecture with that database
>>> > interface backing when they were built by different teams with little
>>> > knowledge of each other."
>>> >
>>> > He gives an example, I will leave it in java as it is simple enough to
>>> > understand:
>>> >
>>> > "class MovieLister...
>>> >
>>> > public Movie[] moviesDirectedBy(String arg) {
>>> > List allMovies = finder.findAll();
>>> > for (Iterator it = allMovies.iterator(); it.hasNext();) {
>>> > Movie movie = (Movie) it.next();
>>> > if (!movie.getDirector().equals(arg)) it.remove();
>>> > }
>>> > return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
>>> >
>>> > }"
>>> >
>>> > The question is how to provide the finder object in a decoupled
>>> matter, a
>>> > naive approach would be:
>>> >
>>> > " private MovieFinder finder;
>>> >
>>> > public MovieLister() {
>>> > finder = new ColonDelimitedMovieFinder("movies1.txt");
>>> >
>>> > }"
>>> >
>>> > Which couples the MovieLister to the specific ColonDelimitedMovieFinder
>>> > class.
>>> >
>>> > Fowler explains how to decouple using an IoC framework or a Service
>>> Locator.
>>> > In Java and .Net IoC is used most of the time. I Googled how this
>>> problem is
>>> > approached in Smalltalk/Pharo, and I generally I found answers "that
>>> is easy
>>> > to do in Smalltalk, so there is no need of a framework", what I miss
>>> is a
>>> > description on *how* to do that:
>>> >
>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>> > https://stackoverflow.com/questions/2684326/is-there-a-depen
>>> dency-injection-framework-for-smalltalk
>>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>>> /347477#347477
>>> >
>>> > I know that in Smalltalk I can make MovieLister to receive, upon
>>> > construction, a class representing MovieFinder and call it construction
>>> > message. As long an object that responds to this message is provided,
>>> I can
>>> > create as many derivations I want and the MovieLister will be
>>> decoupled from
>>> > the MovieFinder. That way, however, I still have to wire things by
>>> hand, and
>>> > I am not sure if this is what I am supposed to do in order to solve the
>>> > decouple problem.
>>> >
>>> > Can you explain me how this is done in Pharo? It's is usually wiring by
>>> > hand? Is there a simple construction that deals with the wiring
>>> problem that
>>> > I cannot foresee?
>>> >
>>> > Thanks in advance,
>>> > Vitor
>>> >
>>> >
>>> >
>>>
>>>
>>
>
June 5, 2017
Re: [Pharo-users] STON Question
by Stephane Ducasse
Hi offray
Thanks but pillar ha a conf since several years and it is working well. Now
I'm revisiting the implementation of cocoon
because I want to have it simpler independent of magritte and better tested.
Now I just want to add a new functionality to output a configuration file
from the
objects and in Pillar the configuration objects hold more complex
***objects***.
So just taking the object and turning it in ston does not work.
Stef
On Mon, Jun 5, 2017 at 6:23 PM, Offray Vladimir Luna Cárdenas <
offray.luna(a)mutabit.com> wrote:
> Hi,
>
> Maybe what I'm doing in Grafoscopio could help.
>
> I have a %metadata node which contains all configuration options for the
> production of the document (as shown in the image below). Exporting a
> document consist in looking for these nodes while traversing the notebook
> tree and applying that options in the proper place. You can see the source
> code of the current notebook STON file at [1], the exported markdown file
> at [2] and the exported PDF at [3]. As you can see I have pretty good
> control of the configuration of the document using this option (and a
> single place to manage all, without endless small files and folders for a
> document, but event that exporting options as split folders and docs, could
> be added also).
> [1] http://mutabit.com/repos.fossil/grafoscopio/artifact/fb25442038a0d4a1
> [2] http://mutabit.com/repos.fossil/grafoscopio/artifact?
> name=59245142cf93590b&txt=1
> [3] http://mutabit.com/repos.fossil/grafoscopio/doc/tip/
> Docs/En/Books/Manual/manual.pdf
>
>
>
> Cheers,
>
> Offray
>
>
> On 05/06/17 01:58, Stephane Ducasse wrote:
>
> Sven I know what Ston is :)
>
> Now Pillar dev used Ston as input and it works. Then with some hooks they
> let the user convert the strings
> into specific objects and this is ok.
> Now I want to add export in Ston and for configurations I need to control
> for the application and not as a ston object the value saved.
> For example a file reference should not be just a file reference in Ston
> but
> a string relative the the baseDirectory of the configuration.
>
> So I thought that I can build a hook and control the call to Ston (convert
> the object before to the correct values) and export.
> It should be working now doing this I found myself redoing the output of
> Ston.
> So I will do it. Then I thought that may be I could reuse this logic.
>
> Stef
>
>
>
> On Sun, Jun 4, 2017 at 11:49 PM, Sven Van Caekenberghe <sven(a)stfx.eu>
> wrote:
>
>> Stef,
>>
>> STON is like FUEL, it can write any object to a stream and read it back.
>> Although you can customise how this is done, only one way of doing so is
>> supported (i.e. you cannot change the format for each application).
>>
>> People have used STON for various applications now, including for
>> configuration stuff (because it is a textual format that is easy to read).
>>
>> I would suggest you just try to see what your config looks like once you
>> have the objects in Pharo.
>>
>> STON toStringPretty: myConfig.
>>
>> Then we can see how to tune the representation.
>>
>> Sven
>>
>> > On 4 Jun 2017, at 22:58, Stephane Ducasse <stepharo.self(a)gmail.com>
>> wrote:
>> >
>> > Hi sven
>> >
>> > I'm working on a new configuration frameworks similar to the one use
>> pillar.conf.
>> >
>> > So basically I have
>> >
>> > ston := '{
>> > "newLine":#unix,
>> > "separateOutputFiles":true
>> > }'.
>> > and I want to recreate it.
>> >
>> > So I did
>> >
>> > Object >> toConfigurationString
>> >
>> > ^ STON toString: self
>> >
>> > SimpleConfiguration >> exportStream
>> >
>> > ^ String streamContents: [ :str |
>> > str << '{' .
>> > self propertiesKeysAndValuesDo: [ :key :value|
>> > str << key toConfigurationString.
>> > str << ':'.
>> > str << value toConfigurationString.
>> > str << ','.
>> > str lf.
>> > ].
>> > str << '}'.
>> > str contents
>> > ]
>> >
>> > The idea is that for special configuration values people should be able
>> to define
>> > how to go from the object to configuration.
>> > For example for some FileReference I want to have just the path up to
>> the baseDirectory.
>> >
>> > Now I wonder if I could not better reuse ston.
>> > I saw the stonOn:
>> > but I did not look further because I was wondering how the writer where
>> passed.
>> >
>> > Any feedback is welcome.
>> >
>> > Stef (now bed time).
>> >
>>
>>
>>
>
>
June 5, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Ben Coman
On Tue, Jun 6, 2017 at 1:26 AM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
wrote:
> Thanks for the answer Ben and Stephane.
>
> I already read A Mentoring Course on Smalltalk, Valloud, there is nothing
> there I could use in this case :( . I will look after for The Design
> Patterns Smalltalk Companion. Most of the sources provided I already know
> of or went in the same lines lines of what I have already found.
>
> About TDD, I am experienced with the discipline and have tested it on
> Pharo living system already, but I could not understand how this is related
> with object wiring, DI and service locator.
>
I guess I don't properly understand your need and those topics. That was
my quick pass. Now if I take the time to actually read Fowler's long
article
"the inversion is about how they lookup a plugin implementation ... to
ensure that any user of a plugin follows some convention that allows a
separate assembler module to inject the implementation into the lister."
"The basic idea of the Dependency Injection is to have a separate object,
an assembler, that populates a field in the lister class with an
appropriate implementation for the finder interface. There are three main
styles of dependency injection. The names I'm using for them are
Constructor Injection, Setter Injection, and Interface Injection."
Now there was too much syntactical noise in those Java examples for me to
think clearly, so I converted them all to Smalltalk.
##CONSTRUCTOR INJECTION
Object subclass: MovieLister
instanceVariables: 'finder'
MovieLister class >> newWith: aFinder
^ self basicNew initializeWith: aFinder
MovieLister >> initializeWith: aFinder
finder := aFinder
ColonMovieFinder class >> newWith: aFilename
^ self basicNew initializeWith: aFilename
ColonMovieFinder >> initializeWith: aFilename
filename := aFilename.
ConstructorInjectionContainer >> new
container := DefaultContainer new. "the article doesn't specify where
this comes from"
finderParams := ConstantParameter newWith: 'movies1.txt'.
container registerComponentInterface: MovieFinderInterface
implementation: ColonMovieFinder
params: finderParams.
container registerComponentImplementation: MovieLister
^container
to be used like this...
ConstructorInjectionTest >> testWithContainer
container := ConstructorInjectionContainer new.
lister := container getComponentInstance( MovieLister ).
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
The article poorly defines registerComponentXXX: or getComponentInstance:
methods, so I don't dwell on them. I presume its little relevant to the
main theme.
##SETTER INJECTION
MovieLister >> setFinder: aFinder
finder := aFinder.
ColonMovieFinder >> setFilename: aFilename
filename := aFilename.
SetterInjectionTest >> testWithConfigurationFile
ctx := SomeXmlApplicationConfiguration on: 'config.xml'.
lister := ctx getConfigOf: 'MovieLister'.
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
##INTERFACE INJECTION
MovieLister >> injectFinder: aFinder
finder := aFinder
ColonMovieFinder >> injectFilename: aFilename
filename := aFilename
InterfaceInjectionTest >> configureContainer
container := InterfaceInjectionContainer new.
self registerComponents.
self registerInjectors.
container start.
InterfaceInjectionTest >> registerComponents
container registerComponent: 'MovieLister' with: MovieLister.
container registerComponent: 'MovieFinder' with: ColonMovieFinder.
InterfaceInjectionTest >> registerInjectors
container registerInjector: Injector with: (container lookup:
'MovieFinder').
container registerInjector: InjectorFinderFilename with:
FinderFilenameInjector new.
ColonMovieFinder >> inject: anObject
anObject injectFinder: self.
FinderFilenameInjector >> inject: anObject
anObject injectFilename: 'movies1.txt'.
InterfaceInjectionTester >> testInterface
self configureContainer.
lister := container lookup: 'MovieLister'.
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
The article doesn't define InterfaceInjectionContainer, but I guess it
could look like this...
InterfaceInjectionContainer >> registerComponent: componentName with:
aComponent
container ifNil: [ container := Dictionary new].
container at: componentName put: aComponent
InterfaceInjectionContainer >> lookup: componentName
^ container at: componentName
##SERVICE LOCATOR
"The basic idea behind a service locator is to have an object that knows
how to get hold of all of the services that an application might need. So a
service locator for this application would have a method that returns a
movie finder when one is needed. Of course this just shifts the burden a
tad, we still have to get the locator into the lister"
MovieLister >> initialize
finder := ServiceLocator movieFinder.
Object subclass: ServiceLocator
instanceVariable: 'movieFinder'
classVariable: 'SoleInstance'
ServiceLocator class >> load: aServiceLocator
SoleInstance := aServiceLocator
ServiceLocator class >> soleInstance
^ SoleInstance
ServiceLocator class >> movieFinder
^ self soleInstance movieFinder
ServiceLocator >> movieFinder
^movieFinder
ServiceLocatorTest >> configure
ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
newWith: 'movies1.txt'))
ServiceLocator class >> newWith: aMovieFinder
^ self basicNew initializeWithFinder: aMovieFinder
ServiceLocator >> initializeWithFinder: aMovieFinder
movieFinder := aMovieFinder
ServiceLocatorTest >> testSimple
self configure.
lister := MovieLister new.
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
So it seems that a service locator is just a Singleton pattern having a
class variable for each service of interest ??
So in good faith** I ask... "Is it any more complicated than that?"
**Since its taken me a couple of hours to convert the Java to this point so
I stopped reading to seek your feedback.
Is that enough insight to adapt to your needs, or is there something else
further down the article that invalidates my analysis?
>
> From ben:
>
> "I'm not really familiar with IoC or DI patterns, so just taking your
>> example at face value, in Pharo I'd do...
>>
>> MovieLister>>moviesDirectedBy: director
>> allMovies := finder allMovies.
>> ^ allMovies select: [ :movie | movie getDirector = director ].
>> "although typically #getDirector would be renamed #director"
>>
>> MovieLister>>finder: movieFinder
>> finder := movieFinder.
>>
>> to be used like this...
>> lister := MovieLister new finder: (ColonDelimitedMovieFinder on:
>> 'movies1.txt').
>> movies := lister moviesDirectedBy: 'Tarantino'."
>
>
So per Fowler, the above is equivalent to "Setter Injection with Spring"
>
> and Stephane:
>
> Why don't you simply pass the class and use that class in your MovieLister?
>>
>> MovieLister new
>> finderClass: MySuperCoolFinderClass
>>
>> ...
>> MovieLister finder
>> finderClass new .....
>>
>> What is wrong with that.
>
>
> That was what I meant when I said: "I know that in Smalltalk I can make
> MovieLister to receive, upon construction, a class representing MovieFinder
> and call it construction message.". The code I had in mind is a bit of
> mix from the one provided by you both:
>
> MovieLister>>moviesDirectedBy: director
> allMovies := finder allMovies.
> ^ allMovies select: [ :movie | movie getDirector = director ].
> "although typically #getDirector would be renamed #director"
>
> MovieLister>>finder: aMovieFinderBuilder
> finder := aMovieFinderClass new.
>
> to be used like this...
> lister := MovieLister new finder: (ColonDelimitedMovieFinder
> builderOn: 'movies1.txt').
> movies := lister moviesDirectedBy: 'Tarantino'."
>
> But that means I will have to wire dependencies by hand whenever I create
> a MovieLister and seek through code when and if those dependencies change.
> When there are lot's of dependencies it's is a considerable and tedious
> work. Let's see an image from Fowlers article:
>
> [image: Inline image 1]
>
> In this case, the service locator provides me with an instance and I
> configure the instance in the assembler, the scheme is alike for an IoC,
> and that would mean my implementation could be like this:
>
>
> MovieLister>>moviesDirectedBy: director
> allMovies := finder allMovies.
> ^ allMovies select: [ :movie | movie getDirector = director ].
> "although typically #getDirector would be renamed #director"
>
> MovieLister>>initialize
> finder := ServiceLocator locate: FinderClass <--- This would bring
> the instance of finder class configured by the assembler
>
No, like this...
finder := ServiceLocation movieFinder.
Now if you want to store a class rather than an instance as I did higher
up, you just do this...
Object subclass: ServiceLocator
instanceVariable: 'movieFinderClass'
classVariable: 'SoleInstance'
ServiceLocator class >> movieFinder
^ self soleInstance movieFinderClass new
>
>
> to be used like this...
> lister := MovieLister new.
> movies := lister moviesDirectedBy: 'Tarantino'."
>
> and the assembler:
>
> Assember class>>configure:
> aMap put: (ColonDelimitedMovieFinder builderOn: 'movies1.txt') at:
> FinderClass
>
Assembler class>>configure
ServiceLocator load:
(ServiceLocator new
movieFinder: (ColonMovieFinder newWith: 'movies1.txt')
otherService: MyCustomService new)
>
> My assembler and service locator could be even more elaborated, and
> provide a different MovieFinder in test scope, for different classes or
> wharever.
>
Really, the test should not be updating the class variable global like
this...
ServiceLocatorTest >> configure
ServiceLocator load: (ServiceLocator newWith: (ColonMovieFinder
newWith: 'movies1.txt'))
you probably want something like (its rough but shows the point...)
Object subclass: #MovieLister
instanceVariables: 'serviceLocator'
MovieLister >> initialize
serviceLocator ifNil: [ serviceLocator := ServiceLocator soleInstance ].
finder := serviceLocator movieFinder.
MovieLister class >> newWithServiceLocator: aServiceLocator
^ (self basicNew initializeWithServiceLocator: aServiceLocator)
initialize.
MovieLister >> initializeWithServiceLocator: aServiceLocator
serviceLocator := aServiceLocator
ServiceLocatorTest >> testSimple2
lister := MovieLister newWithServiceLocator: (ServiceLocator newWith:
(ColonMovieFinder newWith: 'movies1.txt')).
movies = lister moviesDirectedBy: 'Sergio Leone'.
self assert: (movies includes: 'Once Upon a Time in the West')
cheers -ben
>
> It is a little convenience for Smalltalk, I will give that, but I was
> wandering if there was something alike in Pharo, by your answers I assuming
> there is nothing like that.
>
>
>
> On Mon, Jun 5, 2017 at 6:41 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
> wrote:
>
>> Why don't you simply pass the class and use that class in your
>> MovieLister?
>>
>> MovieLister new
>> finderClass: MySuperCoolFinderClass
>>
>> ...
>> MovieLister finder
>> finderClass new .....
>>
>> What is wrong with that.
>>
>> If you do not want to have a reference at runtime to a Finder then you
>> need to use announcement and registration.
>>
>> Stef
>>
>>
>>
>> On Sun, Jun 4, 2017 at 11:17 PM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
>> wrote:
>> > Hello,
>> >
>> > I would like to know how people in Pharo ecosystem do to deal with
>> object
>> > wiring, as described by Marting Fowler in
>> > https://martinfowler.com/articles/injection.html#FormsOfDepe
>> ndencyInjection:
>> >
>> > "A common issue to deal with is how to wire together different
>> elements: how
>> > do you fit together this web controller architecture with that database
>> > interface backing when they were built by different teams with little
>> > knowledge of each other."
>> >
>> > He gives an example, I will leave it in java as it is simple enough to
>> > understand:
>> >
>> > "class MovieLister...
>> >
>> > public Movie[] moviesDirectedBy(String arg) {
>> > List allMovies = finder.findAll();
>> > for (Iterator it = allMovies.iterator(); it.hasNext();) {
>> > Movie movie = (Movie) it.next();
>> > if (!movie.getDirector().equals(arg)) it.remove();
>> > }
>> > return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
>> >
>> > }"
>> >
>> > The question is how to provide the finder object in a decoupled matter,
>> a
>> > naive approach would be:
>> >
>> > " private MovieFinder finder;
>> >
>> > public MovieLister() {
>> > finder = new ColonDelimitedMovieFinder("movies1.txt");
>> >
>> > }"
>> >
>> > Which couples the MovieLister to the specific ColonDelimitedMovieFinder
>> > class.
>> >
>> > Fowler explains how to decouple using an IoC framework or a Service
>> Locator.
>> > In Java and .Net IoC is used most of the time. I Googled how this
>> problem is
>> > approached in Smalltalk/Pharo, and I generally I found answers "that is
>> easy
>> > to do in Smalltalk, so there is no need of a framework", what I miss is
>> a
>> > description on *how* to do that:
>> >
>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>> > https://stackoverflow.com/questions/2684326/is-there-a-depen
>> dency-injection-framework-for-smalltalk
>> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
>> /347477#347477
>> >
>> > I know that in Smalltalk I can make MovieLister to receive, upon
>> > construction, a class representing MovieFinder and call it construction
>> > message. As long an object that responds to this message is provided, I
>> can
>> > create as many derivations I want and the MovieLister will be decoupled
>> from
>> > the MovieFinder. That way, however, I still have to wire things by
>> hand, and
>> > I am not sure if this is what I am supposed to do in order to solve the
>> > decouple problem.
>> >
>> > Can you explain me how this is done in Pharo? It's is usually wiring by
>> > hand? Is there a simple construction that deals with the wiring problem
>> that
>> > I cannot foresee?
>> >
>> > Thanks in advance,
>> > Vitor
>> >
>> >
>> >
>>
>>
>
June 5, 2017
Re: [Pharo-users] STON Question
by Offray Vladimir Luna Cárdenas
Hi,
Maybe what I'm doing in Grafoscopio could help.
I have a %metadata node which contains all configuration options for the
production of the document (as shown in the image below). Exporting a
document consist in looking for these nodes while traversing the
notebook tree and applying that options in the proper place. You can see
the source code of the current notebook STON file at [1], the exported
markdown file at [2] and the exported PDF at [3]. As you can see I have
pretty good control of the configuration of the document using this
option (and a single place to manage all, without endless small files
and folders for a document, but event that exporting options as split
folders and docs, could be added also).
[1] http://mutabit.com/repos.fossil/grafoscopio/artifact/fb25442038a0d4a1
[2]
http://mutabit.com/repos.fossil/grafoscopio/artifact?name=59245142cf93590b&…
[3]
http://mutabit.com/repos.fossil/grafoscopio/doc/tip/Docs/En/Books/Manual/ma…
Cheers,
Offray
On 05/06/17 01:58, Stephane Ducasse wrote:
> Sven I know what Ston is :)
>
> Now Pillar dev used Ston as input and it works. Then with some hooks
> they let the user convert the strings
> into specific objects and this is ok.
> Now I want to add export in Ston and for configurations I need to
> control for the application and not as a ston object the value saved.
> For example a file reference should not be just a file reference in
> Ston but
> a string relative the the baseDirectory of the configuration.
>
> So I thought that I can build a hook and control the call to Ston
> (convert the object before to the correct values) and export.
> It should be working now doing this I found myself redoing the output
> of Ston.
> So I will do it. Then I thought that may be I could reuse this logic.
>
> Stef
>
>
>
> On Sun, Jun 4, 2017 at 11:49 PM, Sven Van Caekenberghe <sven(a)stfx.eu
> <mailto:sven@stfx.eu>> wrote:
>
> Stef,
>
> STON is like FUEL, it can write any object to a stream and read it
> back. Although you can customise how this is done, only one way of
> doing so is supported (i.e. you cannot change the format for each
> application).
>
> People have used STON for various applications now, including for
> configuration stuff (because it is a textual format that is easy
> to read).
>
> I would suggest you just try to see what your config looks like
> once you have the objects in Pharo.
>
> STON toStringPretty: myConfig.
>
> Then we can see how to tune the representation.
>
> Sven
>
> > On 4 Jun 2017, at 22:58, Stephane Ducasse
> <stepharo.self(a)gmail.com <mailto:stepharo.self@gmail.com>> wrote:
> >
> > Hi sven
> >
> > I'm working on a new configuration frameworks similar to the one
> use pillar.conf.
> >
> > So basically I have
> >
> > ston := '{
> > "newLine":#unix,
> > "separateOutputFiles":true
> > }'.
> > and I want to recreate it.
> >
> > So I did
> >
> > Object >> toConfigurationString
> >
> > ^ STON toString: self
> >
> > SimpleConfiguration >> exportStream
> >
> > ^ String streamContents: [ :str |
> > str << '{' .
> > self propertiesKeysAndValuesDo: [ :key :value|
> > str << key toConfigurationString.
> > str << ':'.
> > str << value toConfigurationString.
> > str << ','.
> > str lf.
> > ].
> > str << '}'.
> > str contents
> > ]
> >
> > The idea is that for special configuration values people should
> be able to define
> > how to go from the object to configuration.
> > For example for some FileReference I want to have just the path
> up to the baseDirectory.
> >
> > Now I wonder if I could not better reuse ston.
> > I saw the stonOn:
> > but I did not look further because I was wondering how the
> writer where passed.
> >
> > Any feedback is welcome.
> >
> > Stef (now bed time).
> >
>
>
>
June 5, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Vitor Medina Cruz
Thanks for the answer Ben and Stephane.
I already read A Mentoring Course on Smalltalk, Valloud, there is nothing
there I could use in this case :( . I will look after for The Design
Patterns Smalltalk Companion. Most of the sources provided I already know
of or went in the same lines lines of what I have already found.
About TDD, I am experienced with the discipline and have tested it on Pharo
living system already, but I could not understand how this is related with
object wiring, DI and service locator.
>From ben:
"I'm not really familiar with IoC or DI patterns, so just taking your
> example at face value, in Pharo I'd do...
>
> MovieLister>>moviesDirectedBy: director
> allMovies := finder allMovies.
> ^ allMovies select: [ :movie | movie getDirector = director ].
> "although typically #getDirector would be renamed #director"
>
> MovieLister>>finder: movieFinder
> finder := movieFinder.
>
> to be used like this...
> lister := MovieLister new finder: (ColonDelimitedMovieFinder on:
> 'movies1.txt').
> movies := lister moviesDirectedBy: 'Tarantino'."
and Stephane:
Why don't you simply pass the class and use that class in your MovieLister?
>
> MovieLister new
> finderClass: MySuperCoolFinderClass
>
> ...
> MovieLister finder
> finderClass new .....
>
> What is wrong with that.
That was what I meant when I said: "I know that in Smalltalk I can make
MovieLister to receive, upon construction, a class representing MovieFinder
and call it construction message.". The code I had in mind is a bit of mix
from the one provided by you both:
MovieLister>>moviesDirectedBy: director
allMovies := finder allMovies.
^ allMovies select: [ :movie | movie getDirector = director ].
"although typically #getDirector would be renamed #director"
MovieLister>>finder: aMovieFinderBuilder
finder := aMovieFinderClass new.
to be used like this...
lister := MovieLister new finder: (ColonDelimitedMovieFinder builderOn:
'movies1.txt').
movies := lister moviesDirectedBy: 'Tarantino'."
But that means I will have to wire dependencies by hand whenever I create a
MovieLister and seek through code when and if those dependencies change.
When there are lot's of dependencies it's is a considerable and tedious
work. Let's see an image from Fowlers article:
[image: Inline image 1]
In this case, the service locator provides me with an instance and I
configure the instance in the assembler, the scheme is alike for an IoC,
and that would mean my implementation could be like this:
MovieLister>>moviesDirectedBy: director
allMovies := finder allMovies.
^ allMovies select: [ :movie | movie getDirector = director ].
"although typically #getDirector would be renamed #director"
MovieLister>>initialize
finder := ServiceLocator locate: FinderClass <--- This would bring
the instance of finder class configured by the assembler
to be used like this...
lister := MovieLister new.
movies := lister moviesDirectedBy: 'Tarantino'."
and the assembler:
Assember class>>configure:
aMap put: (ColonDelimitedMovieFinder builderOn: 'movies1.txt') at:
FinderClass
My assembler and service locator could be even more elaborated, and provide
a different MovieFinder in test scope, for different classes or wharever.
It is a little convenience for Smalltalk, I will give that, but I was
wandering if there was something alike in Pharo, by your answers I assuming
there is nothing like that.
If you do not want to have a reference at runtime to a Finder then you
> need to use announcement and registration.
I didn't understand that, could you elaborate?
On Mon, Jun 5, 2017 at 6:41 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
wrote:
> Why don't you simply pass the class and use that class in your MovieLister?
>
> MovieLister new
> finderClass: MySuperCoolFinderClass
>
> ...
> MovieLister finder
> finderClass new .....
>
> What is wrong with that.
>
> If you do not want to have a reference at runtime to a Finder then you
> need to use announcement and registration.
>
> Stef
>
>
>
> On Sun, Jun 4, 2017 at 11:17 PM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
> wrote:
> > Hello,
> >
> > I would like to know how people in Pharo ecosystem do to deal with object
> > wiring, as described by Marting Fowler in
> > https://martinfowler.com/articles/injection.html#
> FormsOfDependencyInjection:
> >
> > "A common issue to deal with is how to wire together different elements:
> how
> > do you fit together this web controller architecture with that database
> > interface backing when they were built by different teams with little
> > knowledge of each other."
> >
> > He gives an example, I will leave it in java as it is simple enough to
> > understand:
> >
> > "class MovieLister...
> >
> > public Movie[] moviesDirectedBy(String arg) {
> > List allMovies = finder.findAll();
> > for (Iterator it = allMovies.iterator(); it.hasNext();) {
> > Movie movie = (Movie) it.next();
> > if (!movie.getDirector().equals(arg)) it.remove();
> > }
> > return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
> >
> > }"
> >
> > The question is how to provide the finder object in a decoupled matter, a
> > naive approach would be:
> >
> > " private MovieFinder finder;
> >
> > public MovieLister() {
> > finder = new ColonDelimitedMovieFinder("movies1.txt");
> >
> > }"
> >
> > Which couples the MovieLister to the specific ColonDelimitedMovieFinder
> > class.
> >
> > Fowler explains how to decouple using an IoC framework or a Service
> Locator.
> > In Java and .Net IoC is used most of the time. I Googled how this
> problem is
> > approached in Smalltalk/Pharo, and I generally I found answers "that is
> easy
> > to do in Smalltalk, so there is no need of a framework", what I miss is a
> > description on *how* to do that:
> >
> > https://stackoverflow.com/questions/243905/smalltalk-and-ioc
> > https://stackoverflow.com/questions/2684326/is-there-a-
> dependency-injection-framework-for-smalltalk
> > https://stackoverflow.com/questions/243905/smalltalk-
> and-ioc/347477#347477
> >
> > I know that in Smalltalk I can make MovieLister to receive, upon
> > construction, a class representing MovieFinder and call it construction
> > message. As long an object that responds to this message is provided, I
> can
> > create as many derivations I want and the MovieLister will be decoupled
> from
> > the MovieFinder. That way, however, I still have to wire things by hand,
> and
> > I am not sure if this is what I am supposed to do in order to solve the
> > decouple problem.
> >
> > Can you explain me how this is done in Pharo? It's is usually wiring by
> > hand? Is there a simple construction that deals with the wiring problem
> that
> > I cannot foresee?
> >
> > Thanks in advance,
> > Vitor
> >
> >
> >
>
>
June 5, 2017
XPath has unresolved dependencies
by Henrik Nergaard
Hi,
Loading XPath from the catalog browser into the latest image raises a warning that there are unresolved references, and that the package depends on the following classes: XMLHighlighter, XMLHighlighterDefaults, GLMXMLHighlighterTextStylerDecorator.
The regular XPath works fine ignoring the warnings, but inspecting an XML document and clicking the XPath pane gives an error.
Best regards,
Henrik
June 5, 2017
Re: [Pharo-users] Deprecating Auto-fix: WOW
by Stephane Ducasse
:)
little improvements one at a time but many many many times :)
On Sat, Jun 3, 2017 at 3:32 PM, Sean P. DeNigris <sean(a)clipperadams.com> wrote:
> Either I died and went to heaven, or my Pharo 6 image just ported all my
> deprecated methods auto-magically. Very cool! Thanks!!!
>
>
>
> -----
> Cheers,
> Sean
> --
> View this message in context: http://forum.world.st/Deprecating-Auto-fix-WOW-tp4949164.html
> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>
June 5, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Stephane Ducasse
Why don't you simply pass the class and use that class in your MovieLister?
MovieLister new
finderClass: MySuperCoolFinderClass
...
MovieLister finder
finderClass new .....
What is wrong with that.
If you do not want to have a reference at runtime to a Finder then you
need to use announcement and registration.
Stef
On Sun, Jun 4, 2017 at 11:17 PM, Vitor Medina Cruz <vitormcruz(a)gmail.com> wrote:
> Hello,
>
> I would like to know how people in Pharo ecosystem do to deal with object
> wiring, as described by Marting Fowler in
> https://martinfowler.com/articles/injection.html#FormsOfDependencyInjection:
>
> "A common issue to deal with is how to wire together different elements: how
> do you fit together this web controller architecture with that database
> interface backing when they were built by different teams with little
> knowledge of each other."
>
> He gives an example, I will leave it in java as it is simple enough to
> understand:
>
> "class MovieLister...
>
> public Movie[] moviesDirectedBy(String arg) {
> List allMovies = finder.findAll();
> for (Iterator it = allMovies.iterator(); it.hasNext();) {
> Movie movie = (Movie) it.next();
> if (!movie.getDirector().equals(arg)) it.remove();
> }
> return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
>
> }"
>
> The question is how to provide the finder object in a decoupled matter, a
> naive approach would be:
>
> " private MovieFinder finder;
>
> public MovieLister() {
> finder = new ColonDelimitedMovieFinder("movies1.txt");
>
> }"
>
> Which couples the MovieLister to the specific ColonDelimitedMovieFinder
> class.
>
> Fowler explains how to decouple using an IoC framework or a Service Locator.
> In Java and .Net IoC is used most of the time. I Googled how this problem is
> approached in Smalltalk/Pharo, and I generally I found answers "that is easy
> to do in Smalltalk, so there is no need of a framework", what I miss is a
> description on *how* to do that:
>
> https://stackoverflow.com/questions/243905/smalltalk-and-ioc
> https://stackoverflow.com/questions/2684326/is-there-a-dependency-injection…
> https://stackoverflow.com/questions/243905/smalltalk-and-ioc/347477#347477
>
> I know that in Smalltalk I can make MovieLister to receive, upon
> construction, a class representing MovieFinder and call it construction
> message. As long an object that responds to this message is provided, I can
> create as many derivations I want and the MovieLister will be decoupled from
> the MovieFinder. That way, however, I still have to wire things by hand, and
> I am not sure if this is what I am supposed to do in order to solve the
> decouple problem.
>
> Can you explain me how this is done in Pharo? It's is usually wiring by
> hand? Is there a simple construction that deals with the wiring problem that
> I cannot foresee?
>
> Thanks in advance,
> Vitor
>
>
>
June 5, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by phil@highoctane.be
Coupling this with Olek's work on the DataFrame could really come handy.
Phil
On Mon, Jun 5, 2017 at 9:14 AM, Stephane Ducasse <stepharo.self(a)gmail.com>
wrote:
> Hi Steffen
>
>
> > The short answer is that the compact notation turned out to work much
> better
> > for me in my code, especially, if multiple transducers are involved. But
> > that's my personal taste. You can choose which suits you better. In fact,
> >
> > 1000 take.
> >
> > just sits on top and simply calls
> >
> > Take number: 1000.
>
> To me this is much much better.
>
>
> > If the need arises, we could of course factor the compact notation out
> into
> > a separate package.
> Good idea
>
> Btw, would you prefer (Take n: 1000) over (Take number:
> > 1000)?
>
> I tend to prefer explicit selector :)
>
>
> > Damien, you're right, I experimented with additional styles. Right now,
> we
> > already have in the basic Transducer package:
> >
> > (collection transduce: #squared map * 1000 take. "which is equal to"
> > (collection transduce: #squared map) transduce: 1000 take.
> >
> > Basically, one can split #transduce:reduce:init: into single calls of
> > #transduce:, #reduce:, and #init:, depending on the needs.
> > I also have an (unfinished) extension, that allows to write:
> >
> > (collection transduce map: #squared) take: 1000.
>
> To me this is much mre readable.
> I cannot and do not want to use the other forms.
>
>
> > This feels familiar, but becomes a bit hard to read if more than two
> steps
> > are needed.
> >
> > collection transduce
> > map: #squared;
> > take: 1000.
>
> Why this is would hard to read. We do that all the time everywhere.
>
>
> > I think, this alternative would reads nicely. But as the message chain
> has
> > to modify the underlying object (an eduction), very snaky side effects
> may
> > occur. E.g., consider
> >
> > eduction := collection transduce.
> > squared := eduction map: #squared.
> > take := squared take: 1000.
> >
> > Now, all three variables hold onto the same object, which first squares
> all
> > elements and than takes the first 1000.
>
> This is because the programmer did not understand what he did. No?
>
>
>
> Stef
>
> PS: I played with infinite stream and iteration back in 1993 in CLOS.
> Now I do not like to mix things because it breaks my flow of thinking.
>
>
> >
> > Best,
> > Steffen
> >
> >
> >
> >
> >
> > Am .06.2017, 21:28 Uhr, schrieb Damien Pollet
> > <damien.pollet+pharo(a)gmail.com>:
> >
> >> If I recall correctly, there is an alternate protocol that looks more
> like
> >> xtreams or the traditional select/collect iterations.
> >>
> >> On 2 June 2017 at 21:12, Stephane Ducasse <stepharo.self(a)gmail.com>
> wrote:
> >>
> >>> I have a design question
> >>>
> >>> why the library is implemented in functional style vs messages?
> >>> I do not see why this is needed. To my eyes the compact notation
> >>> goes against readibility of code and it feels ad-hoc in Smalltalk.
> >>>
> >>>
> >>> I really prefer
> >>>
> >>> square := Map function: #squared.
> >>> take := Take number: 1000.
> >>>
> >>> Because I know that I can read it and understand it.
> >>> From that perspective I prefer Xtreams.
> >>>
> >>> Stef
> >>>
> >>>
> >>>
> >>>
> >>>
> >>>
> >>>
> >>>
> >>>
> >>> On Wed, May 31, 2017 at 2:23 PM, Steffen Märcker <merkste(a)web.de>
> wrote:
> >>>
> >>>> Hi,
> >>>>
> >>>> I am the developer of the library 'Transducers' for VisualWorks. It
> was
> >>>> formerly known as 'Reducers', but this name was a poor choice. I'd
> like
> >>>> to
> >>>> port it to Pharo, if there is any interest on your side. I hope to
> learn
> >>>> more about Pharo in this process, since I am mainly a VW guy. And most
> >>>> likely, I will come up with a bunch of questions. :-)
> >>>>
> >>>> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be
> very
> >>>> happy to hear your optinions, questions and I hope we can start a
> >>>> fruitful
> >>>> discussion - even if there is not Pharo port yet.
> >>>>
> >>>> Best, Steffen
> >>>>
> >>>>
> >>>>
> >>>> Transducers are building blocks that encapsulate how to process
> elements
> >>>> of a data sequence independently of the underlying input and output
> >>>> source.
> >>>>
> >>>>
> >>>>
> >>>> # Overview
> >>>>
> >>>> ## Encapsulate
> >>>> Implementations of enumeration methods, such as #collect:, have the
> >>>> logic
> >>>> how to process a single element in common.
> >>>> However, that logic is reimplemented each and every time. Transducers
> >>>> make
> >>>> it explicit and facilitate re-use and coherent behavior.
> >>>> For example:
> >>>> - #collect: requires mapping: (aBlock1 map)
> >>>> - #select: requires filtering: (aBlock2 filter)
> >>>>
> >>>>
> >>>> ## Compose
> >>>> In practice, algorithms often require multiple processing steps, e.g.,
> >>>> mapping only a filtered set of elements.
> >>>> Transducers are inherently composable, and hereby, allow to make the
> >>>> combination of steps explicit.
> >>>> Since transducers do not build intermediate collections, their
> >>>> composition
> >>>> is memory-efficient.
> >>>> For example:
> >>>> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map
> elements"
> >>>>
> >>>>
> >>>> ## Re-Use
> >>>> Transducers are decoupled from the input and output sources, and
> hence,
> >>>> they can be reused in different contexts.
> >>>> For example:
> >>>> - enumeration of collections
> >>>> - processing of streams
> >>>> - communicating via channels
> >>>>
> >>>>
> >>>>
> >>>> # Usage by Example
> >>>>
> >>>> We build a coin flipping experiment and count the occurrence of heads
> >>>> and
> >>>> tails.
> >>>>
> >>>> First, we associate random numbers with the sides of a coin.
> >>>>
> >>>> scale := [:x | (x * 2 + 1) floor] map.
> >>>> sides := #(heads tails) replace.
> >>>>
> >>>> Scale is a transducer that maps numbers x between 0 and 1 to 1 and 2.
> >>>> Sides is a transducer that replaces the numbers with heads an tails by
> >>>> lookup in an array.
> >>>> Next, we choose a number of samples.
> >>>>
> >>>> count := 1000 take.
> >>>>
> >>>> Count is a transducer that takes 1000 elements from a source.
> >>>> We keep track of the occurrences of heads an tails using a bag.
> >>>>
> >>>> collect := [:bag :c | bag add: c; yourself].
> >>>>
> >>>> Collect is binary block (reducing function) that collects events in a
> >>>> bag.
> >>>> We assemble the experiment by transforming the block using the
> >>>> transducers.
> >>>>
> >>>> experiment := (scale * sides * count) transform: collect.
> >>>>
> >>>> From left to right we see the steps involved: scale, sides, count
> and
> >>>> collect.
> >>>> Transforming assembles these steps into a binary block (reducing
> >>>> function)
> >>>> we can use to run the experiment.
> >>>>
> >>>> samples := Random new
> >>>> reduce: experiment
> >>>> init: Bag new.
> >>>>
> >>>> Here, we use #reduce:init:, which is mostly similar to #inject:into:.
> >>>> To execute a transformation and a reduction together, we can use
> >>>> #transduce:reduce:init:.
> >>>>
> >>>> samples := Random new
> >>>> transduce: scale * sides * count
> >>>> reduce: collect
> >>>> init: Bag new.
> >>>>
> >>>> We can also express the experiment as data-flow using #<~.
> >>>> This enables us to build objects that can be re-used in other
> >>>> experiments.
> >>>>
> >>>> coin := sides <~ scale <~ Random new.
> >>>> flip := Bag <~ count.
> >>>>
> >>>> Coin is an eduction, i.e., it binds transducers to a source and
> >>>> understands #reduce:init: among others.
> >>>> Flip is a transformed reduction, i.e., it binds transducers to a
> >>>> reducing
> >>>> function and an initial value.
> >>>> By sending #<~, we draw further samples from flipping the coin.
> >>>>
> >>>> samples := flip <~ coin.
> >>>>
> >>>> This yields a new Bag with another 1000 samples.
> >>>>
> >>>>
> >>>>
> >>>> # Basic Concepts
> >>>>
> >>>> ## Reducing Functions
> >>>>
> >>>> A reducing function represents a single step in processing a data
> >>>> sequence.
> >>>> It takes an accumulated result and a value, and returns a new
> >>>> accumulated
> >>>> result.
> >>>> For example:
> >>>>
> >>>> collect := [:col :e | col add: e; yourself].
> >>>> sum := #+.
> >>>>
> >>>> A reducing function can also be ternary, i.e., it takes an accumulated
> >>>> result, a key and a value.
> >>>> For example:
> >>>>
> >>>> collect := [:dic :k :v | dict at: k put: v; yourself].
> >>>>
> >>>> Reducing functions may be equipped with an optional completing action.
> >>>> After finishing processing, it is invoked exactly once, e.g., to free
> >>>> resources.
> >>>>
> >>>> stream := [:str :e | str nextPut: each; yourself] completing:
> >>>> #close.
> >>>> absSum := #+ completing: #abs
> >>>>
> >>>> A reducing function can end processing early by signaling Reduced
> with a
> >>>> result.
> >>>> This mechanism also enables the treatment of infinite sources.
> >>>>
> >>>> nonNil := [:res :e | e ifNil: [Reduced signalWith: res] ifFalse:
> >>>> [res]].
> >>>>
> >>>> The primary approach to process a data sequence is the reducing
> protocol
> >>>> with the messages #reduce:init: and #transduce:reduce:init: if
> >>>> transducers
> >>>> are involved.
> >>>> The behavior is similar to #inject:into: but in addition it takes care
> >>>> of:
> >>>> - handling binary and ternary reducing functions,
> >>>> - invoking the completing action after finishing, and
> >>>> - stopping the reduction if Reduced is signaled.
> >>>> The message #transduce:reduce:init: just combines the transformation
> and
> >>>> the reducing step.
> >>>>
> >>>> However, as reducing functions are step-wise in nature, an application
> >>>> may
> >>>> choose other means to process its data.
> >>>>
> >>>>
> >>>> ## Reducibles
> >>>>
> >>>> A data source is called reducible if it implements the reducing
> >>>> protocol.
> >>>> Default implementations are provided for collections and streams.
> >>>> Additionally, blocks without an argument are reducible, too.
> >>>> This allows to adapt to custom data sources without additional effort.
> >>>> For example:
> >>>>
> >>>> "XStreams adaptor"
> >>>> xstream := filename reading.
> >>>> reducible := [[xstream get] on: Incomplete do: [Reduced signal]].
> >>>>
> >>>> "natural numbers"
> >>>> n := 0.
> >>>> reducible := [n := n+1].
> >>>>
> >>>>
> >>>> ## Transducers
> >>>>
> >>>> A transducer is an object that transforms a reducing function into
> >>>> another.
> >>>> Transducers encapsulate common steps in processing data sequences,
> such
> >>>> as
> >>>> map, filter, concatenate, and flatten.
> >>>> A transducer transforms a reducing function into another via
> #transform:
> >>>> in order to add those steps.
> >>>> They can be composed using #* which yields a new transducer that does
> >>>> both
> >>>> transformations.
> >>>> Most transducers require an argument, typically blocks, symbols or
> >>>> numbers:
> >>>>
> >>>> square := Map function: #squared.
> >>>> take := Take number: 1000.
> >>>>
> >>>> To facilitate compact notation, the argument types implement
> >>>> corresponding
> >>>> methods:
> >>>>
> >>>> squareAndTake := #squared map * 1000 take.
> >>>>
> >>>> Transducers requiring no argument are singletons and can be accessed
> by
> >>>> their class name.
> >>>>
> >>>> flattenAndDedupe := Flatten * Dedupe.
> >>>>
> >>>>
> >>>>
> >>>> # Advanced Concepts
> >>>>
> >>>> ## Data flows
> >>>>
> >>>> Processing a sequence of data can often be regarded as a data flow.
> >>>> The operator #<~ allows define a flow from a data source through
> >>>> processing steps to a drain.
> >>>> For example:
> >>>>
> >>>> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
> >>>> fileOut writeStream <~ #isSeparator filter <~ fileIn readStream.
> >>>>
> >>>> In both examples #<~ is only used to set up the data flow using
> reducing
> >>>> functions and transducers.
> >>>> In contrast to streams, transducers are completely independent from
> >>>> input
> >>>> and output sources.
> >>>> Hence, we have a clear separation of reading data, writing data and
> >>>> processing elements.
> >>>> - Sources know how to iterate over data with a reducing function,
> e.g.,
> >>>> via #reduce:init:.
> >>>> - Drains know how to collect data using a reducing function.
> >>>> - Transducers know how to process single elements.
> >>>>
> >>>>
> >>>> ## Reductions
> >>>>
> >>>> A reduction binds an initial value or a block yielding an initial
> value
> >>>> to
> >>>> a reducing function.
> >>>> The idea is to define a ready-to-use process that can be applied in
> >>>> different contexts.
> >>>> Reducibles handle reductions via #reduce: and #transduce:reduce:
> >>>> For example:
> >>>>
> >>>> sum := #+ init: 0.
> >>>> sum1 := #(1 1 1) reduce: sum.
> >>>> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
> >>>>
> >>>> asSet := [:set :e | set add: e; yourself] initializer: [Set new].
> >>>> set1 := #(1 1 1) reduce: asSet.
> >>>> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
> >>>>
> >>>> By combining a transducer with a reduction, a process can be further
> >>>> modified.
> >>>>
> >>>> sumOdds := sum <~ #odd filter
> >>>> setOdds := asSet <~ #odd filter
> >>>>
> >>>>
> >>>> ## Eductions
> >>>>
> >>>> An eduction combines a reducible data sources with a transducer.
> >>>> The idea is to define a transformed (virtual) data source that needs
> not
> >>>> to be stored in memory.
> >>>>
> >>>> odds1 := #odd filter <~ #(1 2 3) readStream.
> >>>> odds2 := #odd filter <~ (1 to 1000).
> >>>>
> >>>> Depending on the underlying source, eductions can be processed once
> >>>> (streams, e.g., odds1) or multiple times (collections, e.g., odds2).
> >>>> Since no intermediate data is stored, transducers actions are lazy,
> >>>> i.e.,
> >>>> they are invoked each time the eduction is processed.
> >>>>
> >>>>
> >>>>
> >>>> # Origins
> >>>>
> >>>> Transducers is based on the same-named Clojure library and its ideas.
> >>>> Please see:
> >>>> http://clojure.org/transducers
> >>>>
> >>>>
> >
>
>
>
June 5, 2017
Re: [Pharo-users] Saving selected changes in Monticello
by Peter Uhnak
Komitter could indeed help you, see https://www.peteruhnak.com/blog/2016/08/12/fine-grained-committing-and-exte…
Peter
On Mon, Jun 05, 2017 at 08:27:23AM +0200, serge.stinckwich(a)gmail.com wrote:
> Kommiter available in default image allows you do cherry pick quite easily.
>
> Envoyé de mon iPhone
>
> > Le 5 juin 2017 à 07:14, Ben Coman <btc(a)openinworld.com> a écrit :
> >
> >
> >
> >> On Mon, Jun 5, 2017 at 10:12 AM, Andreas Sunardi <a.sunardi(a)gmail.com> wrote:
> >> I have a half done changes in my image, but I need to distribute the other changes that are done. I thought I was going to do this all at once, but now I realize I should split this into 2 commit versions.
> >>
> >> Is there a way in Monticello to say save my changes, but not this and that changes? I can't seem to find it nor in books. How do people deal with this situation?
> >
> > AFAIK, Monticello cannot cherry pick. One work around is probably something like...
> > 1. Save the mcz locally
> > 2. Merge back into a fresh image selecting only the bits you want.
> > 3. Save as a second mcz.
> > One issue is that the second mcz will have the first mcz as an ancestor, so before 2 you might create a new changeset to file out after 2, and load that into a second new image. yuck!
> >
> > Another alternative might be to use Tools > ChangeSorter to move the code you want to exclude from the mcz to a changeset, file that out and then revert that code in the image. After save the package to a mcz, reload the changeset.
> >
> > cheers -ben
June 5, 2017
Re: [Pharo-users] snap morphs/windows to each other when dragging
by Stephane Ducasse
I do not know that by default.
Especially since the drag and drop is when the mous is inside.
this is anice scenario for bloc :)
On Sun, Jun 4, 2017 at 2:51 PM, Peter Uhnak <i.uhnak(a)gmail.com> wrote:
> Hi,
>
> is it possible to tell windows to "snap" to other windows when dragging?
>
> So e.g. when I am dragging Playground window, it will try to snap side by side with a close-by another window, so they don't overlap (unless I e.g. press shift or something).
>
> Thanks,
> Peter
>
June 5, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Stephane Ducasse
Hi Steffen
> The short answer is that the compact notation turned out to work much better
> for me in my code, especially, if multiple transducers are involved. But
> that's my personal taste. You can choose which suits you better. In fact,
>
> 1000 take.
>
> just sits on top and simply calls
>
> Take number: 1000.
To me this is much much better.
> If the need arises, we could of course factor the compact notation out into
> a separate package.
Good idea
Btw, would you prefer (Take n: 1000) over (Take number:
> 1000)?
I tend to prefer explicit selector :)
> Damien, you're right, I experimented with additional styles. Right now, we
> already have in the basic Transducer package:
>
> (collection transduce: #squared map * 1000 take. "which is equal to"
> (collection transduce: #squared map) transduce: 1000 take.
>
> Basically, one can split #transduce:reduce:init: into single calls of
> #transduce:, #reduce:, and #init:, depending on the needs.
> I also have an (unfinished) extension, that allows to write:
>
> (collection transduce map: #squared) take: 1000.
To me this is much mre readable.
I cannot and do not want to use the other forms.
> This feels familiar, but becomes a bit hard to read if more than two steps
> are needed.
>
> collection transduce
> map: #squared;
> take: 1000.
Why this is would hard to read. We do that all the time everywhere.
> I think, this alternative would reads nicely. But as the message chain has
> to modify the underlying object (an eduction), very snaky side effects may
> occur. E.g., consider
>
> eduction := collection transduce.
> squared := eduction map: #squared.
> take := squared take: 1000.
>
> Now, all three variables hold onto the same object, which first squares all
> elements and than takes the first 1000.
This is because the programmer did not understand what he did. No?
Stef
PS: I played with infinite stream and iteration back in 1993 in CLOS.
Now I do not like to mix things because it breaks my flow of thinking.
>
> Best,
> Steffen
>
>
>
>
>
> Am .06.2017, 21:28 Uhr, schrieb Damien Pollet
> <damien.pollet+pharo(a)gmail.com>:
>
>> If I recall correctly, there is an alternate protocol that looks more like
>> xtreams or the traditional select/collect iterations.
>>
>> On 2 June 2017 at 21:12, Stephane Ducasse <stepharo.self(a)gmail.com> wrote:
>>
>>> I have a design question
>>>
>>> why the library is implemented in functional style vs messages?
>>> I do not see why this is needed. To my eyes the compact notation
>>> goes against readibility of code and it feels ad-hoc in Smalltalk.
>>>
>>>
>>> I really prefer
>>>
>>> square := Map function: #squared.
>>> take := Take number: 1000.
>>>
>>> Because I know that I can read it and understand it.
>>> From that perspective I prefer Xtreams.
>>>
>>> Stef
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> On Wed, May 31, 2017 at 2:23 PM, Steffen Märcker <merkste(a)web.de> wrote:
>>>
>>>> Hi,
>>>>
>>>> I am the developer of the library 'Transducers' for VisualWorks. It was
>>>> formerly known as 'Reducers', but this name was a poor choice. I'd like
>>>> to
>>>> port it to Pharo, if there is any interest on your side. I hope to learn
>>>> more about Pharo in this process, since I am mainly a VW guy. And most
>>>> likely, I will come up with a bunch of questions. :-)
>>>>
>>>> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be very
>>>> happy to hear your optinions, questions and I hope we can start a
>>>> fruitful
>>>> discussion - even if there is not Pharo port yet.
>>>>
>>>> Best, Steffen
>>>>
>>>>
>>>>
>>>> Transducers are building blocks that encapsulate how to process elements
>>>> of a data sequence independently of the underlying input and output
>>>> source.
>>>>
>>>>
>>>>
>>>> # Overview
>>>>
>>>> ## Encapsulate
>>>> Implementations of enumeration methods, such as #collect:, have the
>>>> logic
>>>> how to process a single element in common.
>>>> However, that logic is reimplemented each and every time. Transducers
>>>> make
>>>> it explicit and facilitate re-use and coherent behavior.
>>>> For example:
>>>> - #collect: requires mapping: (aBlock1 map)
>>>> - #select: requires filtering: (aBlock2 filter)
>>>>
>>>>
>>>> ## Compose
>>>> In practice, algorithms often require multiple processing steps, e.g.,
>>>> mapping only a filtered set of elements.
>>>> Transducers are inherently composable, and hereby, allow to make the
>>>> combination of steps explicit.
>>>> Since transducers do not build intermediate collections, their
>>>> composition
>>>> is memory-efficient.
>>>> For example:
>>>> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map elements"
>>>>
>>>>
>>>> ## Re-Use
>>>> Transducers are decoupled from the input and output sources, and hence,
>>>> they can be reused in different contexts.
>>>> For example:
>>>> - enumeration of collections
>>>> - processing of streams
>>>> - communicating via channels
>>>>
>>>>
>>>>
>>>> # Usage by Example
>>>>
>>>> We build a coin flipping experiment and count the occurrence of heads
>>>> and
>>>> tails.
>>>>
>>>> First, we associate random numbers with the sides of a coin.
>>>>
>>>> scale := [:x | (x * 2 + 1) floor] map.
>>>> sides := #(heads tails) replace.
>>>>
>>>> Scale is a transducer that maps numbers x between 0 and 1 to 1 and 2.
>>>> Sides is a transducer that replaces the numbers with heads an tails by
>>>> lookup in an array.
>>>> Next, we choose a number of samples.
>>>>
>>>> count := 1000 take.
>>>>
>>>> Count is a transducer that takes 1000 elements from a source.
>>>> We keep track of the occurrences of heads an tails using a bag.
>>>>
>>>> collect := [:bag :c | bag add: c; yourself].
>>>>
>>>> Collect is binary block (reducing function) that collects events in a
>>>> bag.
>>>> We assemble the experiment by transforming the block using the
>>>> transducers.
>>>>
>>>> experiment := (scale * sides * count) transform: collect.
>>>>
>>>> From left to right we see the steps involved: scale, sides, count and
>>>> collect.
>>>> Transforming assembles these steps into a binary block (reducing
>>>> function)
>>>> we can use to run the experiment.
>>>>
>>>> samples := Random new
>>>> reduce: experiment
>>>> init: Bag new.
>>>>
>>>> Here, we use #reduce:init:, which is mostly similar to #inject:into:.
>>>> To execute a transformation and a reduction together, we can use
>>>> #transduce:reduce:init:.
>>>>
>>>> samples := Random new
>>>> transduce: scale * sides * count
>>>> reduce: collect
>>>> init: Bag new.
>>>>
>>>> We can also express the experiment as data-flow using #<~.
>>>> This enables us to build objects that can be re-used in other
>>>> experiments.
>>>>
>>>> coin := sides <~ scale <~ Random new.
>>>> flip := Bag <~ count.
>>>>
>>>> Coin is an eduction, i.e., it binds transducers to a source and
>>>> understands #reduce:init: among others.
>>>> Flip is a transformed reduction, i.e., it binds transducers to a
>>>> reducing
>>>> function and an initial value.
>>>> By sending #<~, we draw further samples from flipping the coin.
>>>>
>>>> samples := flip <~ coin.
>>>>
>>>> This yields a new Bag with another 1000 samples.
>>>>
>>>>
>>>>
>>>> # Basic Concepts
>>>>
>>>> ## Reducing Functions
>>>>
>>>> A reducing function represents a single step in processing a data
>>>> sequence.
>>>> It takes an accumulated result and a value, and returns a new
>>>> accumulated
>>>> result.
>>>> For example:
>>>>
>>>> collect := [:col :e | col add: e; yourself].
>>>> sum := #+.
>>>>
>>>> A reducing function can also be ternary, i.e., it takes an accumulated
>>>> result, a key and a value.
>>>> For example:
>>>>
>>>> collect := [:dic :k :v | dict at: k put: v; yourself].
>>>>
>>>> Reducing functions may be equipped with an optional completing action.
>>>> After finishing processing, it is invoked exactly once, e.g., to free
>>>> resources.
>>>>
>>>> stream := [:str :e | str nextPut: each; yourself] completing:
>>>> #close.
>>>> absSum := #+ completing: #abs
>>>>
>>>> A reducing function can end processing early by signaling Reduced with a
>>>> result.
>>>> This mechanism also enables the treatment of infinite sources.
>>>>
>>>> nonNil := [:res :e | e ifNil: [Reduced signalWith: res] ifFalse:
>>>> [res]].
>>>>
>>>> The primary approach to process a data sequence is the reducing protocol
>>>> with the messages #reduce:init: and #transduce:reduce:init: if
>>>> transducers
>>>> are involved.
>>>> The behavior is similar to #inject:into: but in addition it takes care
>>>> of:
>>>> - handling binary and ternary reducing functions,
>>>> - invoking the completing action after finishing, and
>>>> - stopping the reduction if Reduced is signaled.
>>>> The message #transduce:reduce:init: just combines the transformation and
>>>> the reducing step.
>>>>
>>>> However, as reducing functions are step-wise in nature, an application
>>>> may
>>>> choose other means to process its data.
>>>>
>>>>
>>>> ## Reducibles
>>>>
>>>> A data source is called reducible if it implements the reducing
>>>> protocol.
>>>> Default implementations are provided for collections and streams.
>>>> Additionally, blocks without an argument are reducible, too.
>>>> This allows to adapt to custom data sources without additional effort.
>>>> For example:
>>>>
>>>> "XStreams adaptor"
>>>> xstream := filename reading.
>>>> reducible := [[xstream get] on: Incomplete do: [Reduced signal]].
>>>>
>>>> "natural numbers"
>>>> n := 0.
>>>> reducible := [n := n+1].
>>>>
>>>>
>>>> ## Transducers
>>>>
>>>> A transducer is an object that transforms a reducing function into
>>>> another.
>>>> Transducers encapsulate common steps in processing data sequences, such
>>>> as
>>>> map, filter, concatenate, and flatten.
>>>> A transducer transforms a reducing function into another via #transform:
>>>> in order to add those steps.
>>>> They can be composed using #* which yields a new transducer that does
>>>> both
>>>> transformations.
>>>> Most transducers require an argument, typically blocks, symbols or
>>>> numbers:
>>>>
>>>> square := Map function: #squared.
>>>> take := Take number: 1000.
>>>>
>>>> To facilitate compact notation, the argument types implement
>>>> corresponding
>>>> methods:
>>>>
>>>> squareAndTake := #squared map * 1000 take.
>>>>
>>>> Transducers requiring no argument are singletons and can be accessed by
>>>> their class name.
>>>>
>>>> flattenAndDedupe := Flatten * Dedupe.
>>>>
>>>>
>>>>
>>>> # Advanced Concepts
>>>>
>>>> ## Data flows
>>>>
>>>> Processing a sequence of data can often be regarded as a data flow.
>>>> The operator #<~ allows define a flow from a data source through
>>>> processing steps to a drain.
>>>> For example:
>>>>
>>>> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
>>>> fileOut writeStream <~ #isSeparator filter <~ fileIn readStream.
>>>>
>>>> In both examples #<~ is only used to set up the data flow using reducing
>>>> functions and transducers.
>>>> In contrast to streams, transducers are completely independent from
>>>> input
>>>> and output sources.
>>>> Hence, we have a clear separation of reading data, writing data and
>>>> processing elements.
>>>> - Sources know how to iterate over data with a reducing function, e.g.,
>>>> via #reduce:init:.
>>>> - Drains know how to collect data using a reducing function.
>>>> - Transducers know how to process single elements.
>>>>
>>>>
>>>> ## Reductions
>>>>
>>>> A reduction binds an initial value or a block yielding an initial value
>>>> to
>>>> a reducing function.
>>>> The idea is to define a ready-to-use process that can be applied in
>>>> different contexts.
>>>> Reducibles handle reductions via #reduce: and #transduce:reduce:
>>>> For example:
>>>>
>>>> sum := #+ init: 0.
>>>> sum1 := #(1 1 1) reduce: sum.
>>>> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
>>>>
>>>> asSet := [:set :e | set add: e; yourself] initializer: [Set new].
>>>> set1 := #(1 1 1) reduce: asSet.
>>>> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
>>>>
>>>> By combining a transducer with a reduction, a process can be further
>>>> modified.
>>>>
>>>> sumOdds := sum <~ #odd filter
>>>> setOdds := asSet <~ #odd filter
>>>>
>>>>
>>>> ## Eductions
>>>>
>>>> An eduction combines a reducible data sources with a transducer.
>>>> The idea is to define a transformed (virtual) data source that needs not
>>>> to be stored in memory.
>>>>
>>>> odds1 := #odd filter <~ #(1 2 3) readStream.
>>>> odds2 := #odd filter <~ (1 to 1000).
>>>>
>>>> Depending on the underlying source, eductions can be processed once
>>>> (streams, e.g., odds1) or multiple times (collections, e.g., odds2).
>>>> Since no intermediate data is stored, transducers actions are lazy,
>>>> i.e.,
>>>> they are invoked each time the eduction is processed.
>>>>
>>>>
>>>>
>>>> # Origins
>>>>
>>>> Transducers is based on the same-named Clojure library and its ideas.
>>>> Please see:
>>>> http://clojure.org/transducers
>>>>
>>>>
>
June 5, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Stephane Ducasse
About NG this is strange but may be we were working on an old VW version.
- I can help producing a nice document :)
>>
>
> Do you mean like the booklets published over the last weeks? This would be
> great.
>
yes now I do not want to help promoting a syntax that alienates me (and
others because other people reported the saem to me). :)
Do you have an idea, how to add a package comment to the simple file-out it
> used? I think, a simple message send should suffice.
>
produce a monticello package, select the package and comment.
>>>
June 5, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Stephane Ducasse
We do not work with fileouts :)
You should produce packages with also a configuration and published them on
smalltalkhub or git and
in the MetaRepository.
You can also add package comments
On Sat, Jun 3, 2017 at 10:29 PM, Steffen Märcker <merkste(a)web.de> wrote:
> Dear all,
>
> attached are updated file-outs. I fixed a couple of annoyances that
> slipped through yesterday evening. Most notable:
>
> 1) Random generator now works.
> 2) Early termination via Reduced exception does MNU anymore.
> 3) Printing a transducer holding a block does not MNU anymore.
>
> Please, give it a spin and tell me your impressions. (At least) The
> coin-flipping the example from the package comment works now:
>
> scale := [:x | (x * 2 + 1) floor] map.
> sides := #(heads tails) replace.
> count := 1000 take.
> collect := [:bag :c | bag add: c; yourself].
> experiment := (scale * sides * count) transform: collect.
> "experiment cannot be re-used"
> samples := Random new
> reduce: experiment
> init: Bag new.
> "transform and reduce in one step"
> samples := Random new
> transduce: scale * sides * count
> reduce: collect
> init: Bag new.
> "assemble coin (eduction) and flip (reduction) objects"
> coin := sides <~ scale <~ Random new.
> flip := Bag <~ count.
> "flip coin =)"
> samples := flip <~ coin.
>
> Cheers!
> Steffen
>
>
>
> Am .06.2017, 23:08 Uhr, schrieb Steffen Märcker <merkste(a)web.de>:
>
> Thanks, this appears to work. Attached you'll find the file-out from
>> VisualWorks and the file-out from Pharo (includes package comment).
>>
>> Cheers!
>> Steffen
>>
>>
>> Am .06.2017, 20:06 Uhr, schrieb Yanni Chiu <yanni.code(a)gmail.com>:
>>
>> To get the extension methods into the Transducers package, the following
>>> worked for me - edit the category to have the prefix '*Transducers-'
>>>
>>> 2710c2710
>>>
>>> < !Number methodsFor: 'transforming' stamp: ' 2/6/17 15:38'!
>>>
>>> ---
>>>
>>> !Number methodsFor: '*Transducers-transforming' stamp: ' 2/6/17 15:38'!
>>>>
>>>
>>>
>>> On Fri, Jun 2, 2017 at 11:05 AM, Steffen Märcker <merkste(a)web.de> wrote:
>>>
>>> Dear all,
>>>>
>>>> thanks for the many suggestions. I didn't had time to test all
>>>> import/export ways yet. But for now, I can report on two:
>>>>
>>>> 1) NGFileOuter
>>>> Unfortunately It raised several MNUs in my image. I'll investigate them
>>>> later.
>>>>
>>>> 2) FileOut30 (VW Contributed)
>>>> I was able to file out the code except for the package definition.
>>>> Replacing {category: ''} in the class definitions with {package:
>>>> 'Transducers'} fixed that. However, methods that extend existing classes
>>>> did not end up in the Transducers package. Is there a similar easy
>>>> change
>>>> to the file-out making that happen? Also I'd like to add the package
>>>> comment if that's possible.
>>>>
>>>> Most things appear to work as far as I can see. Two exceptions:
>>>> 1) Random is a subclass of Stream in VW and in Pharo it is not. Hence,
>>>> I'll have to copy some methods from Stream to Random.
>>>> 2) I used #beImmutable in VW but I couldn't yet figure out how to make
>>>> objects immutable in Pharo.
>>>>
>>>> However, until the tests are ported, I cannot guarantee. Porting the
>>>> test
>>>> suite will be another beast, since I rely on the excellent
>>>> mocking/stubbing
>>>> library DoubleAgents by Randy Coulman. I am not sure how I will handle
>>>> that. In general, I think it would be really worth the effort to be
>>>> ported
>>>> to Pharo, too. DoubleAgents is pretty powerful and produces easy to read
>>>> and understand mocking/stubbing code. Personally, I prefer it clearly,
>>>> e.g., over Mocketry (no offence intended!).
>>>>
>>>> Attached you'll find the file-out that I loaded into Pharo. The issues
>>>> above are not addressed yet. However, the following example works:
>>>>
>>>> | scale sides count collect experiment random samples coin flip |
>>>> scale := [:x | (x * 2 + 1) floor] map.
>>>> sides := #(heads tails) replace.
>>>> count := 1000 take.
>>>> collect := [:bag :c | bag add: c; yourself].
>>>> experiment := (scale * sides * count) transform: collect.
>>>> random := #(0.1 0.3 0.4 0.5 0.6 0.7 0.8 0.9).
>>>>
>>>> samples := random
>>>> reduce: experiment
>>>> init: Bag new.
>>>>
>>>> samples := random
>>>> transduce: scale * sides * count
>>>> reduce: collect
>>>> init: Bag new.
>>>>
>>>> coin := sides <~ scale <~ random.
>>>> flip := Bag <~ count.
>>>>
>>>> samples := flip <~ coin.
>>>>
>>>>
>>>> Best, Steffen
>>>>
>>>>
>>>>
>>>> Am .06.2017, 08:16 Uhr, schrieb Stephane Ducasse
>>>> <stepharo.self(a)gmail.com
>>>> >:
>>>>
>>>> There is a package for that NGFileOuter or something like that on cincom
>>>>
>>>>> store.
>>>>> We used it for mobydic code.
>>>>>
>>>>> On Wed, May 31, 2017 at 6:35 PM, Alexandre Bergel <
>>>>> alexandre.bergel(a)me.com>
>>>>> wrote:
>>>>>
>>>>> If I remember correctly, there is a parcel in VisualWorks to export a
>>>>> file
>>>>>
>>>>>> out (Squeak format).
>>>>>>
>>>>>> @Milton, can you give a hand to Steffen?
>>>>>>
>>>>>> Alexandre
>>>>>> --
>>>>>> _,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
>>>>>> Alexandre Bergel http://www.bergel.eu
>>>>>> ^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
>>>>>>
>>>>>>
>>>>>>
>>>>>> On May 31, 2017, at 10:32 AM, Steffen Märcker <merkste(a)web.de> wrote:
>>>>>>
>>>>>> Thanks for the encouraging response! First question: Which is the
>>>>>> recommended (friction free) way to exchange code between VW and Pharo?
>>>>>>
>>>>>> Cheers!
>>>>>> Steffen
>>>>>>
>>>>>> Am .05.2017, 16:22 Uhr, schrieb Alexandre Bergel <
>>>>>> alexandre.bergel(a)me.com
>>>>>> >:
>>>>>>
>>>>>> I second Sven. This is very exciting!
>>>>>>
>>>>>> Let us know when you have something ready to be tested.
>>>>>>
>>>>>> Alexandre
>>>>>>
>>>>>>
June 5, 2017
Re: [Pharo-users] STON Question
by Stephane Ducasse
Sven I know what Ston is :)
Now Pillar dev used Ston as input and it works. Then with some hooks they
let the user convert the strings
into specific objects and this is ok.
Now I want to add export in Ston and for configurations I need to control
for the application and not as a ston object the value saved.
For example a file reference should not be just a file reference in Ston
but
a string relative the the baseDirectory of the configuration.
So I thought that I can build a hook and control the call to Ston (convert
the object before to the correct values) and export.
It should be working now doing this I found myself redoing the output of
Ston.
So I will do it. Then I thought that may be I could reuse this logic.
Stef
On Sun, Jun 4, 2017 at 11:49 PM, Sven Van Caekenberghe <sven(a)stfx.eu> wrote:
> Stef,
>
> STON is like FUEL, it can write any object to a stream and read it back.
> Although you can customise how this is done, only one way of doing so is
> supported (i.e. you cannot change the format for each application).
>
> People have used STON for various applications now, including for
> configuration stuff (because it is a textual format that is easy to read).
>
> I would suggest you just try to see what your config looks like once you
> have the objects in Pharo.
>
> STON toStringPretty: myConfig.
>
> Then we can see how to tune the representation.
>
> Sven
>
> > On 4 Jun 2017, at 22:58, Stephane Ducasse <stepharo.self(a)gmail.com>
> wrote:
> >
> > Hi sven
> >
> > I'm working on a new configuration frameworks similar to the one use
> pillar.conf.
> >
> > So basically I have
> >
> > ston := '{
> > "newLine":#unix,
> > "separateOutputFiles":true
> > }'.
> > and I want to recreate it.
> >
> > So I did
> >
> > Object >> toConfigurationString
> >
> > ^ STON toString: self
> >
> > SimpleConfiguration >> exportStream
> >
> > ^ String streamContents: [ :str |
> > str << '{' .
> > self propertiesKeysAndValuesDo: [ :key :value|
> > str << key toConfigurationString.
> > str << ':'.
> > str << value toConfigurationString.
> > str << ','.
> > str lf.
> > ].
> > str << '}'.
> > str contents
> > ]
> >
> > The idea is that for special configuration values people should be able
> to define
> > how to go from the object to configuration.
> > For example for some FileReference I want to have just the path up to
> the baseDirectory.
> >
> > Now I wonder if I could not better reuse ston.
> > I saw the stonOn:
> > but I did not look further because I was wondering how the writer where
> passed.
> >
> > Any feedback is welcome.
> >
> > Stef (now bed time).
> >
>
>
>
June 5, 2017
Re: [Pharo-users] Saving selected changes in Monticello
by serge.stinckwich@gmail.com
Kommiter available in default image allows you do cherry pick quite easily.
Envoyé de mon iPhone
> Le 5 juin 2017 à 07:14, Ben Coman <btc(a)openinworld.com> a écrit :
>
>
>
>> On Mon, Jun 5, 2017 at 10:12 AM, Andreas Sunardi <a.sunardi(a)gmail.com> wrote:
>> I have a half done changes in my image, but I need to distribute the other changes that are done. I thought I was going to do this all at once, but now I realize I should split this into 2 commit versions.
>>
>> Is there a way in Monticello to say save my changes, but not this and that changes? I can't seem to find it nor in books. How do people deal with this situation?
>
> AFAIK, Monticello cannot cherry pick. One work around is probably something like...
> 1. Save the mcz locally
> 2. Merge back into a fresh image selecting only the bits you want.
> 3. Save as a second mcz.
> One issue is that the second mcz will have the first mcz as an ancestor, so before 2 you might create a new changeset to file out after 2, and load that into a second new image. yuck!
>
> Another alternative might be to use Tools > ChangeSorter to move the code you want to exclude from the mcz to a changeset, file that out and then revert that code in the image. After save the package to a mcz, reload the changeset.
>
> cheers -ben
June 5, 2017
Re: [Pharo-users] Saving selected changes in Monticello
by Ben Coman
On Mon, Jun 5, 2017 at 10:12 AM, Andreas Sunardi <a.sunardi(a)gmail.com>
wrote:
> I have a half done changes in my image, but I need to distribute the other
> changes that are done. I thought I was going to do this all at once, but
> now I realize I should split this into 2 commit versions.
>
> Is there a way in Monticello to say save my changes, but not this and that
> changes? I can't seem to find it nor in books. How do people deal with this
> situation?
>
AFAIK, Monticello cannot cherry pick. One work around is probably
something like...
1. Save the mcz locally
2. Merge back into a fresh image selecting only the bits you want.
3. Save as a second mcz.
One issue is that the second mcz will have the first mcz as an ancestor, so
before 2 you might create a new changeset to file out after 2, and load
that into a second new image. yuck!
Another alternative might be to use Tools > ChangeSorter to move the code
you want to exclude from the mcz to a changeset, file that out and then
revert that code in the image. After save the package to a mcz, reload the
changeset.
cheers -ben
June 5, 2017
Re: [Pharo-users] Wiring objects, IoC and Service Locator
by Ben Coman
Sorry I'm not familiar with the pattern, so I don't have a direct answer,
and the following might not have a direct answer either, but in general
I'd strongly suggest
two books for adapting from static OO languages.
1. The Design Patterns Smalltalk Companion, Alpert, Brown & Woolf -
including some discussion on why certain patterns required for static-OO
are redundant in Smalltalk. My naive guess is the Factory, Strategy and/or
Template patterns may apply.
2. A Mentoring Course on Smalltalk, Valloud
On Mon, Jun 5, 2017 at 5:17 AM, Vitor Medina Cruz <vitormcruz(a)gmail.com>
wrote:
> Hello,
>
> I would like to know how people in Pharo ecosystem do to deal with object
> wiring, as described by Marting Fowler in https://martinfowler.com/
> articles/injection.html#FormsOfDependencyInjection:
>
> "A common issue to deal with is how to wire together different elements:
> how do you fit together this web controller architecture with that database
> interface backing when they were built by different teams with little
> knowledge of each other."
>
> He gives an example, I will leave it in java as it is simple enough to
> understand:
>
> "class MovieLister...
>
> public Movie[] moviesDirectedBy(String arg) {
> List allMovies = finder.findAll();
> for (Iterator it = allMovies.iterator(); it.hasNext();) {
> Movie movie = (Movie) it.next();
> if (!movie.getDirector().equals(arg)) it.remove();
> }
> return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
>
> }"
>
> The question is how to provide the finder object in a decoupled matter, a
> naive approach would be:
>
> " private MovieFinder finder;
>
> public MovieLister() {
> finder = new ColonDelimitedMovieFinder("movies1.txt");
>
> }"
>
I'm not really familiar with IoC or DI patterns, so just taking your
example at face value, in Pharo I'd do...
MovieLister>>moviesDirectedBy: director
allMovies := finder allMovies.
^ allMovies select: [ :movie | movie getDirector = director ].
"although typically #getDirector would be renamed #director"
MovieLister>>finder: movieFinder
finder := movieFinder.
to be used like this...
lister := MovieLister new finder: (ColonDelimitedMovieFinder on:
'movies1.txt').
movies := lister moviesDirectedBy: 'Tarantino'.
>
> Which couples the MovieLister to the specific ColonDelimitedMovieFinder
> class.
>
> Fowler explains how to decouple using an IoC framework or a Service
> Locator. In Java and .Net IoC is used most of the time. I Googled how this
> problem is approached in Smalltalk/Pharo, and I generally I found answers
> "that is easy to do in Smalltalk, so there is no need of a framework", what
> I miss is a description on *how* to do that:
>
Just to satisfy my curiosity, I did find... "MVC was invented on Smalltalk
and is arguably the original Inversion of Control framework. ... I think
that IOC or the Dependency Injection pattern solves a problem that doesn't
really exist in the Smalltalk environment. Smalltalk is an untyped dynamic
language and uses message passing to communicate. This makes for objects
that are loosely coupled by nature at the language level"
http://www.weizhishi.tech/questions/296612/smalltalk-and-ioc
And this... "In an explicitly-typed language like C++, C#, or Java, it is
necessary to define an explicit interface for the injected collaborator.
The real collaborator and the substitute both have to implement the
interface. In a dynamically-typed language like Ruby [& Smalltalk],
explicit interfaces are not necessary. We can just take advantage of
'duck-typing'."
http://randycoulman.com/blog/2013/06/04/affordances-dependency-injection/
And GIlad Bracha knows a bit about Java... "I think that if youâre stuck
with a mainstream language, [dependency Injection] may be a reasonable work
around. It requires a significant degree of preplanning, and makes your
application dependent on one more piece of machinery that has nothing to do
with the actual problem the application is trying to solve. On the positive
side, it helps guarantee employment for software engineers. That said, itâs
important to understand that DIFs are just a work around for a deficiency
in the underlying language. So why not get rid of constructors and have a
class declaration create a factory object instead? Well, Smalltalk did just
that a generation ago. Every time you define a class, you define the
factory object for its instances."
https://gbracha.blogspot.com.au/2007/06/constructors-considered-harmful.html
btw, following Randy's example the two steps #new & #finder: should
hidden/combined by renaming MovieLister>>finder:
to MovieLister>>initializeWithFinder:
and adding...
MovieLister class >> newWithFinder: finder
^ self basicNew initializeWithFinder: finder
to be used like this...
lister := MovieLister newWithFinder: (ColonDelimitedMovieFinder on:
'movies1.txt').
movies := lister moviesDirectedBy: 'Tarantino'.
btw, while you are at it, if you haven't done this before, try implementing
this using Smalltalk's version of TDD...
https://www.youtube.com/watch?v=ymITEeAOtEA
https://www.youtube.com/watch?v=XxqZVAOomfM
In a clean image, first implement the following method and run the test,
then fill code as needed just-in-time...
MovieListerTest>>testColonDelimitedFinder
lister := MovieLister newWithFinder: (ColonDelimitedMovieFinder on:
'movies1.txt').
movies := lister moviesDirectedBy: 'Tarantino'.
self assert: (movies includes: 'Pulp Fiction')
> https://stackoverflow.com/questions/243905/smalltalk-and-ioc
> https://stackoverflow.com/questions/2684326/is-there-a-
> dependency-injection-framework-for-smalltalk
> https://stackoverflow.com/questions/243905/smalltalk-and-ioc/347477#347477
>
I see similar comments to my references in these. I hope the bits I've
focussed on are not redundant .
> I know that in Smalltalk I can make MovieLister to receive, upon
> construction, a class representing MovieFinder and call it construction
> message. As long an object that responds to this message is provided, I can
> create as many derivations I want and the MovieLister will be decoupled
> from the MovieFinder.
>
Reading this, I think maybe all I've done with my example is echo this. So
what I'm not clear on is what you mean by "wire things by hand"
> That way, however, I still have to wire things by hand, and I am not sure
> if this is what I am supposed to do in order to solve the decouple problem.
>
I would say use Pharo's TDD approach of coding-from-within-the-debugger.
The beauty of it is not that you get a lot of test coverage. There other
significant benefits are:
A. Your API ends up designed "in the most natural way to be used" since
each time you code how you want to use your API before you define the
implementation.
B. You only need to code the minimum to get that API aspect working. So
you get a faster feedback loop on your design.
C.
You consistency API implementation, you might define a test like...
MovieListerTest>>testAllFinders
AbstractMovieFinder allSubclasses do: [ :finderclass |
lister := MovieLister newWithFinder: (finderclass on: 'movies1.txt').
movies := lister moviesDirectedBy: 'Tarantino'.
self assert: (movies includes: 'Pulp Fiction'). ]
and then each time you add an AbstractMovieFinder subclass, you
implementation is again just work through fixing the tests from within the
debugger.
> Can you explain me how this is done in Pharo? It's is usually wiring by
> hand? Is there a simple construction that deals with the wiring problem
> that I cannot foresee?
>
TDD helps you avoid worrying about problems that might not exist.
cheers -ben
>
> Thanks in advance,
> Vitor
>
>
>
>
June 5, 2017
Saving selected changes in Monticello
by Andreas Sunardi
I have a half done changes in my image, but I need to distribute the other
changes that are done. I thought I was going to do this all at once, but
now I realize I should split this into 2 commit versions.
Is there a way in Monticello to say save my changes, but not this and that
changes? I can't seem to find it nor in books. How do people deal with this
situation?
--
Andreas Sunardi
June 5, 2017
Re: [Pharo-users] Creating a BaselineOf from a ConfigurationOf>>#baselineXyz:
by Hernán Morales Durand
Hi Sean,
I didn't tried too much but you may first have to match the node in the
parse tree. Something like this:
| node |
node := (RBParseTreeRewriter
treeMatching: '`@expr blessing: `#lit'
in: (YourClass >> #baseline01:) parseTree).
(node parent removeNode: node) newSource.
Cheers,
Hernán
2017-06-04 0:48 GMT-03:00 Sean P. DeNigris <sean(a)clipperadams.com>:
> I'm trying to write a rewrite rule, but can't quite get it.
>
> I first want to remove `spec blessing: #baseline.`
>
> I tried the following with no effect:
>
> RBParseTreeRewriter new
> replace: '`@expr blessing: `#lit'
> with: '';
> executeTree: methodTree;
> tree.
>
> NB: If I try to edit the expression instead of remove, by passing something
> like '`@expr assert: `#lit' for #with:, it works
>
> What am I missing here?
>
> Thanks!
>
>
>
> -----
> Cheers,
> Sean
> --
> View this message in context: http://forum.world.st/
> Creating-a-BaselineOf-from-a-ConfigurationOf-baselineXyz-tp4949192.html
> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>
>
June 5, 2017
Re: [Pharo-users] STON Question
by Sven Van Caekenberghe
Stef,
STON is like FUEL, it can write any object to a stream and read it back. Although you can customise how this is done, only one way of doing so is supported (i.e. you cannot change the format for each application).
People have used STON for various applications now, including for configuration stuff (because it is a textual format that is easy to read).
I would suggest you just try to see what your config looks like once you have the objects in Pharo.
STON toStringPretty: myConfig.
Then we can see how to tune the representation.
Sven
> On 4 Jun 2017, at 22:58, Stephane Ducasse <stepharo.self(a)gmail.com> wrote:
>
> Hi sven
>
> I'm working on a new configuration frameworks similar to the one use pillar.conf.
>
> So basically I have
>
> ston := '{
> "newLine":#unix,
> "separateOutputFiles":true
> }'.
> and I want to recreate it.
>
> So I did
>
> Object >> toConfigurationString
>
> ^ STON toString: self
>
> SimpleConfiguration >> exportStream
>
> ^ String streamContents: [ :str |
> str << '{' .
> self propertiesKeysAndValuesDo: [ :key :value|
> str << key toConfigurationString.
> str << ':'.
> str << value toConfigurationString.
> str << ','.
> str lf.
> ].
> str << '}'.
> str contents
> ]
>
> The idea is that for special configuration values people should be able to define
> how to go from the object to configuration.
> For example for some FileReference I want to have just the path up to the baseDirectory.
>
> Now I wonder if I could not better reuse ston.
> I saw the stonOn:
> but I did not look further because I was wondering how the writer where passed.
>
> Any feedback is welcome.
>
> Stef (now bed time).
>
June 4, 2017
Wiring objects, IoC and Service Locator
by Vitor Medina Cruz
Hello,
I would like to know how people in Pharo ecosystem do to deal with object
wiring, as described by Marting Fowler in
https://martinfowler.com/articles/injection.html#FormsOfDependencyInjection:
"A common issue to deal with is how to wire together different elements:
how do you fit together this web controller architecture with that database
interface backing when they were built by different teams with little
knowledge of each other."
He gives an example, I will leave it in java as it is simple enough to
understand:
"class MovieLister...
public Movie[] moviesDirectedBy(String arg) {
List allMovies = finder.findAll();
for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
if (!movie.getDirector().equals(arg)) it.remove();
}
return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
}"
The question is how to provide the finder object in a decoupled matter, a
naive approach would be:
" private MovieFinder finder;
public MovieLister() {
finder = new ColonDelimitedMovieFinder("movies1.txt");
}"
Which couples the MovieLister to the specific ColonDelimitedMovieFinder
class.
Fowler explains how to decouple using an IoC framework or a Service
Locator. In Java and .Net IoC is used most of the time. I Googled how this
problem is approached in Smalltalk/Pharo, and I generally I found answers
"that is easy to do in Smalltalk, so there is no need of a framework", what
I miss is a description on *how* to do that:
https://stackoverflow.com/questions/243905/smalltalk-and-ioc
https://stackoverflow.com/questions/2684326/is-there-a-dependency-injection…
https://stackoverflow.com/questions/243905/smalltalk-and-ioc/347477#347477
I know that in Smalltalk I can make MovieLister to receive, upon
construction, a class representing MovieFinder and call it construction
message. As long an object that responds to this message is provided, I can
create as many derivations I want and the MovieLister will be decoupled
from the MovieFinder. That way, however, I still have to wire things by
hand, and I am not sure if this is what I am supposed to do in order to
solve the decouple problem.
Can you explain me how this is done in Pharo? It's is usually wiring by
hand? Is there a simple construction that deals with the wiring problem
that I cannot foresee?
Thanks in advance,
Vitor
June 4, 2017
STON Question
by Stephane Ducasse
Hi sven
I'm working on a new configuration frameworks similar to the one use
pillar.conf.
So basically I have
ston := '{
"newLine":#unix,
"separateOutputFiles":true
}'.
and I want to recreate it.
So I did
Object >> toConfigurationString
^ STON toString: self
SimpleConfiguration >> exportStream
^ String streamContents: [ :str |
str << '{' .
self propertiesKeysAndValuesDo: [ :key :value|
str << key toConfigurationString.
str << ':'.
str << value toConfigurationString.
str << ','.
str lf.
].
str << '}'.
str contents
]
The idea is that for special configuration values people should be able to
define
how to go from the object to configuration.
For example for some FileReference I want to have just the path up to the
baseDirectory.
Now I wonder if I could not better reuse ston.
I saw the stonOn:
but I did not look further because I was wondering how the writer where
passed.
Any feedback is welcome.
Stef (now bed time).
June 4, 2017
Deadline Extension - SLE 2017 (10th ACM SIGPLAN International Conference on Software Language Engineering)
by Andrei Chis
========================================================================
**Call for Papers** - **Deadline Extension**
**Abstract Submission**: Friday 9, June 2017
**Paper Submission**: Friday 16, June 2017
========================================================================
10th ACM SIGPLAN International Conference on Software Language Engineering
(SLE 2017)
23-24 October 2017, Vancouver, Canada
(Co-located with SPLASH 2017)
General chair:
Benoit Combemale, University of Rennes 1, France
Program co-chairs:
Marjan Mernik, University of Maribor, Slovenia
Bernhard Rumpe, RWTH Aachen University, Germany
Artifact evaluation chairs:
Tanja Mayerhofer, TU Wien, Austria
Laurence Tratt, King's College London, UK
Keynote Speaker:
Peter D. Mosses, Swansea University, UK (http://cs.swan.ac.uk/~cspdm/)
http://conf.researchr.org/track/sle-2017/sle-2017-papers
http://www.sleconf.org/2017
Follow us on twitter: https://twitter.com/sleconf
========================================================================
Software Language Engineering (SLE) is the application of systematic,
disciplined, and measurable approaches to the development, use, deployment,
and maintenance of software languages. The term "software language" is used
broadly, and includes: general-purpose programming languages;
domain-specific languages (e.g. BPMN, Simulink, Modelica); modeling and
metamodeling languages (e.g. SysML and UML); data models and ontologies
(e.g. XML-based and OWL-based languages and vocabularies).
### Important Dates
Fri 9 Jun 2017 - Abstract Submission
Fri 16 Jun 2017 - Paper Submission
Fri 4 Aug 2017 - Author Notification
Thu 10 Aug 2017 - Artifact Submission
Fri 1 Sep 2017 - Artifact Notification
Fri 8 Sep 2017 - Camera Ready Deadline
Sun 22 Oct - SLE workshops
Mon 23 Oct - Tue 24 Oct 2017 - SLE Conference
### Topics of Interest
SLE aims to be broad-minded and inclusive about relevance and scope. We
solicit high-quality contributions in areas ranging from theoretical and
conceptual contributions to tools, techniques, and frameworks in the domain
of language engineering. Topics relevant to SLE cover generic aspects of
software languages development rather than aspects of engineering a
specific language. In particular, SLE is interested in principled
engineering approaches and techniques in the following areas:
* Language Design and Implementation
* Approaches and methodologies for language design
* Static semantics (e.g., design rules, well-formedness constraints)
* Techniques for behavioral / executable semantics
* Generative approaches (incl. code synthesis, compilation)
* Meta-languages, meta-tools, language workbenches
* Language Validation
* Verification and formal methods for languages
* Testing techniques for languages
* Simulation techniques for languages
* Language Integration and Composition
* Coordination of heterogeneous languages and tools
* Mappings between languages (incl. transformation languages)
* Traceability between languages
* Deployment of languages to different platforms
* Language Maintenance
* Software language reuse
* Language evolution
* Language families and variability
* Domain-specific approaches for any aspects of SLE (design,
implementation, validation, maintenance)
* Empirical evaluation and experience reports of language engineering tools
* User studies evaluating usability
* Performance benchmarks
* Industrial applications
### Types of Submissions
* **Research papers**: These should report a substantial research
contribution to SLE or successful application of SLE techniques or both.
Full paper submissions must not exceed 12 pages including bibliography in
ACM SIGPLAN acmart conference style (
http://www.sigplan.org/Resources/Author/)
* **Tool papers**: Because of SLE's interest in tools, we seek papers that
present software tools related to the field of SLE. Selection criteria
include originality of the tool, its innovative aspects, and relevance to
SLE. Any of the SLE topics of interest are appropriate areas for tool
demonstrations. Submissions must provide a tool description of 4 pages
including bibliography in ACM SIGPLAN acmart conference style (
http://www.sigplan.org/Resources/Author/) and a demonstration outline
including screenshots of up to 6 pages. Tool demonstrations must have the
keywords âTool Demoâ or âTool Demonstrationâ in the title. The 4-page tool
description will, if the demonstration is accepted, be published in the
proceedings. The 6-page demonstration outline will be used by the program
committee only for evaluating the submission.
* **Industrial papers**: These should describe real-world application
scenarios of SLE in industry, explained in their context with an analysis
of the challenges that were overcome and the lessons which the audience can
learn from this experience. Industry paper submissions must not exceed 6
pages including bibliography in ACM SIGPLAN acmart conference style (
http://www.sigplan.org/Resources/Author/)
* **New ideas / vision papers**: New ideas papers should describe new,
non-conventional SLE research approaches that depart from standard
practice. They are intended to describe well-defined research ideas that
are at an early stage of investigation. Vision papers are intended to
present new unifying theories about existing SLE research that can lead to
the development of new technologies or approaches. New ideas / vision
papers must not exceed 4 pages including bibliography in ACM SIGPLAN acmart
conference style (http://www.sigplan.org/Resources/Author/)
### Artifact evaluation
SLE will for the second year use an evaluation process for assessing the
quality of artifacts on which papers are based. The aim of this evaluation
process is to foster a culture of experimental reproducibility as well as a
higher quality in the research area as a whole.
Authors of papers accepted for SLE 2017 will be invited to submit
artifacts. Any kind of artifact that is presented in the paper, supplements
the paper with further details, or underlies the paper can be submitted.
This includes, for instance, tools, grammars, metamodels, models, programs,
algorithms, scripts, proofs, datasets, statistical tests, checklists,
surveys, interview scripts, visualizations, annotated bibliographies, and
tutorials.
The submitted artifacts will be reviewed by a dedicated Artifact Evaluation
Committee (AEC). Artifacts that live up to the expectations created by the
paper will receive a badge of approval from the AEC. The approved artifacts
will be invited for inclusion in the electronic conference proceedings
published in the ACM Digital Library. This will ensure the permanent and
durable storage of the artifacts alongside the published papers fostering
the repeatability of experiments, enabling precise comparison with
alternative approaches, and helping the dissemination of the authorâs ideas
in detail.
Participating in the artifact evaluation and publishing approved artifacts
in the ACM Digital Library is voluntary. However, we strongly encourage
authors to consider this possibility as the availability of artifacts will
greatly benefit readers of papers and increase the impact of the work. Note
that the artifact evaluation cannot affect the acceptance of the paper,
because it only happens after the decision about acceptance has been made.
### Publications
All submitted papers will be reviewed by at least three members of the
program committee. All accepted papers, including tool papers, industrial
papers and new ideas / vision papers will be published in ACM Digital
Library.
Selected accepted papers will be invited to a special issue of the Computer
Languages, Systems and Structures (COMLAN) journal.
### Awards
* **Distinguished paper**: Award for most notable paper, as determined by
the PC chairs based on the recommendations of the program committee.
* **Distinguished reviewer**: Award for distinguished reviewer, as
determined by the PC chairs using feedback from the authors.
* **Distinguished artifact**: Award for the artifact most significantly
exceeding expectations, as determined by the AEC chairs based on the
recommendations of the artifact evaluation committee.
### Program Committee
Marjan Mernik (co-chair), University of Maribor, Slovenia
Bernhard Rumpe (co-chair), RWTH Aachen University, Germany
Christian Berger, Chalmers, Sweden
Mark van den Brand, TU Eindhoven, The Netherlands
Ruth Breu, University of Innsbruck, Austria
Jordi Cabot, ICREA, Spain
Walter Cazzola, University of Milan, Italy
Marsha Chechik, University of Toronto, Canada
Tony Clark, Middlesex University, UK
Tom Dinkelaker, Ericsson, Germany
Bernd Fischer, Stellenbosch University, South Africa
Sebastian Gerard, CEA, France
Jeff Gray, University of Alabama, USA
Esther Guerra, Autonomous University of Madrid, Spain
Michael Homer, Victoria University of Wellington, New Zealand
Ralf Lämmel, University of Koblenz-Landau, Germany
Tihamer Levendovszky, Microsoft, USA
Gunter Mussbacher, McGill University, Canada
Terence Parr, University of San Francisco, USA
Jaroslav Porubän, University of Košice, Slovakia
Jan Ringert, Tel Aviv University, Israel
Julia Rubin, University of British Columbia, Canada
Tony Sloane, Macquarie University, Australia
Eugene Syriani, University of Montreal, Canada
Emma Söderberg, Google, Denmark
Eric Van Wyk, University of Minnesota, USA
Jurgen Vinju, CWI, Netherlands
Eric Walkingshaw, Oregon State University, USA
Andreas Wortmann, RWTH Aachen University, Germany
Tian Zhang, Nanjing University, China
### Contact
For any question, please contact the organizers via email: sle2017(a)inria.fr
June 4, 2017
snap morphs/windows to each other when dragging
by Peter Uhnak
Hi,
is it possible to tell windows to "snap" to other windows when dragging?
So e.g. when I am dragging Playground window, it will try to snap side by side with a close-by another window, so they don't overlap (unless I e.g. press shift or something).
Thanks,
Peter
June 4, 2017
Creating a BaselineOf from a ConfigurationOf>>#baselineXyz:
by Sean P. DeNigris
I'm trying to write a rewrite rule, but can't quite get it.
I first want to remove `spec blessing: #baseline.`
I tried the following with no effect:
RBParseTreeRewriter new
replace: '`@expr blessing: `#lit'
with: '';
executeTree: methodTree;
tree.
NB: If I try to edit the expression instead of remove, by passing something
like '`@expr assert: `#lit' for #with:, it works
What am I missing here?
Thanks!
-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/Creating-a-BaselineOf-from-a-ConfigurationOf-baseline…
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 4, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Steffen Märcker
Dear all,
attached are updated file-outs. I fixed a couple of annoyances that
slipped through yesterday evening. Most notable:
1) Random generator now works.
2) Early termination via Reduced exception does MNU anymore.
3) Printing a transducer holding a block does not MNU anymore.
Please, give it a spin and tell me your impressions. (At least) The
coin-flipping the example from the package comment works now:
scale := [:x | (x * 2 + 1) floor] map.
sides := #(heads tails) replace.
count := 1000 take.
collect := [:bag :c | bag add: c; yourself].
experiment := (scale * sides * count) transform: collect.
"experiment cannot be re-used"
samples := Random new
reduce: experiment
init: Bag new.
"transform and reduce in one step"
samples := Random new
transduce: scale * sides * count
reduce: collect
init: Bag new.
"assemble coin (eduction) and flip (reduction) objects"
coin := sides <~ scale <~ Random new.
flip := Bag <~ count.
"flip coin =)"
samples := flip <~ coin.
Cheers!
Steffen
Am .06.2017, 23:08 Uhr, schrieb Steffen Märcker <merkste(a)web.de>:
> Thanks, this appears to work. Attached you'll find the file-out from
> VisualWorks and the file-out from Pharo (includes package comment).
>
> Cheers!
> Steffen
>
>
> Am .06.2017, 20:06 Uhr, schrieb Yanni Chiu <yanni.code(a)gmail.com>:
>
>> To get the extension methods into the Transducers package, the following
>> worked for me - edit the category to have the prefix '*Transducers-'
>>
>> 2710c2710
>>
>> < !Number methodsFor: 'transforming' stamp: ' 2/6/17 15:38'!
>>
>> ---
>>
>>> !Number methodsFor: '*Transducers-transforming' stamp: ' 2/6/17 15:38'!
>>
>>
>> On Fri, Jun 2, 2017 at 11:05 AM, Steffen Märcker <merkste(a)web.de> wrote:
>>
>>> Dear all,
>>>
>>> thanks for the many suggestions. I didn't had time to test all
>>> import/export ways yet. But for now, I can report on two:
>>>
>>> 1) NGFileOuter
>>> Unfortunately It raised several MNUs in my image. I'll investigate them
>>> later.
>>>
>>> 2) FileOut30 (VW Contributed)
>>> I was able to file out the code except for the package definition.
>>> Replacing {category: ''} in the class definitions with {package:
>>> 'Transducers'} fixed that. However, methods that extend existing
>>> classes
>>> did not end up in the Transducers package. Is there a similar easy
>>> change
>>> to the file-out making that happen? Also I'd like to add the package
>>> comment if that's possible.
>>>
>>> Most things appear to work as far as I can see. Two exceptions:
>>> 1) Random is a subclass of Stream in VW and in Pharo it is not. Hence,
>>> I'll have to copy some methods from Stream to Random.
>>> 2) I used #beImmutable in VW but I couldn't yet figure out how to make
>>> objects immutable in Pharo.
>>>
>>> However, until the tests are ported, I cannot guarantee. Porting the
>>> test
>>> suite will be another beast, since I rely on the excellent
>>> mocking/stubbing
>>> library DoubleAgents by Randy Coulman. I am not sure how I will handle
>>> that. In general, I think it would be really worth the effort to be
>>> ported
>>> to Pharo, too. DoubleAgents is pretty powerful and produces easy to
>>> read
>>> and understand mocking/stubbing code. Personally, I prefer it clearly,
>>> e.g., over Mocketry (no offence intended!).
>>>
>>> Attached you'll find the file-out that I loaded into Pharo. The issues
>>> above are not addressed yet. However, the following example works:
>>>
>>> | scale sides count collect experiment random samples coin flip |
>>> scale := [:x | (x * 2 + 1) floor] map.
>>> sides := #(heads tails) replace.
>>> count := 1000 take.
>>> collect := [:bag :c | bag add: c; yourself].
>>> experiment := (scale * sides * count) transform: collect.
>>> random := #(0.1 0.3 0.4 0.5 0.6 0.7 0.8 0.9).
>>>
>>> samples := random
>>> reduce: experiment
>>> init: Bag new.
>>>
>>> samples := random
>>> transduce: scale * sides * count
>>> reduce: collect
>>> init: Bag new.
>>>
>>> coin := sides <~ scale <~ random.
>>> flip := Bag <~ count.
>>>
>>> samples := flip <~ coin.
>>>
>>>
>>> Best, Steffen
>>>
>>>
>>>
>>> Am .06.2017, 08:16 Uhr, schrieb Stephane Ducasse
>>> <stepharo.self(a)gmail.com
>>> >:
>>>
>>> There is a package for that NGFileOuter or something like that on
>>> cincom
>>>> store.
>>>> We used it for mobydic code.
>>>>
>>>> On Wed, May 31, 2017 at 6:35 PM, Alexandre Bergel <
>>>> alexandre.bergel(a)me.com>
>>>> wrote:
>>>>
>>>> If I remember correctly, there is a parcel in VisualWorks to export a
>>>> file
>>>>> out (Squeak format).
>>>>>
>>>>> @Milton, can you give a hand to Steffen?
>>>>>
>>>>> Alexandre
>>>>> --
>>>>> _,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
>>>>> Alexandre Bergel http://www.bergel.eu
>>>>> ^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
>>>>>
>>>>>
>>>>>
>>>>> On May 31, 2017, at 10:32 AM, Steffen Märcker <merkste(a)web.de> wrote:
>>>>>
>>>>> Thanks for the encouraging response! First question: Which is the
>>>>> recommended (friction free) way to exchange code between VW and
>>>>> Pharo?
>>>>>
>>>>> Cheers!
>>>>> Steffen
>>>>>
>>>>> Am .05.2017, 16:22 Uhr, schrieb Alexandre Bergel <
>>>>> alexandre.bergel(a)me.com
>>>>> >:
>>>>>
>>>>> I second Sven. This is very exciting!
>>>>>
>>>>> Let us know when you have something ready to be tested.
>>>>>
>>>>> Alexandre
>>>>>
>>>>>
June 3, 2017
Re: Morphic or forking bug?
by Milan Vavra
Sven's Clock example.
Just unzip & file in.
MyClock.zip <http://forum.world.st/file/n4949170/MyClock.zip>
Best Regards,
Milan Vavra
--
View this message in context: http://forum.world.st/Morphic-or-forking-bug-tp4948727p4949170.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 3, 2017
Re: [Pharo-users] Morphic or forking bug?
by horrido
Okay, let me explain my application...
It displays a Morphic window containing lines of information that are
updateable in real time on a periodic basis. As I indicated in the original
post, the code skeleton is basically:
initA
a := ((StringMorph contents: '####') color: Color white) position: (0@0).
m addMorph: a
initialize
f := Form fromFileNamed: 'hot_air_balloon_mysticmorning.jpg'.
m := ImageMorph new.
m form: f.
self initA.
m openInWindowLabeled: 'Cranky'.
delay := (Delay forSeconds: 5).
[ [ true ] whileTrue: [ a contents: 0 asString. delay wait ] fork
Imagine that #initA creates many such StringMorphs, each displaying a
different kind of information.
In the endless loop, imagine that instead of 'a contents: 0 asString', I'm
updating all of the StringMorphs I created in #initA.
The need to do this in a separate thread is to prevent Pharo from being
completely frozen during the 'delay wait', which is practically all the
time!
Now, I did try Hilaire's suggestion to use Morphic's step protocol instead.
But in my test scenario of closing the app/saving and exiting the
image/restarting the image, repeatedly (in may take 10-20 times), it still
causes the occasional segmentation fault.
So if the problem is updating a structure in the main thread from another
process, then why did Hilaire's suggestion not solve the problem?
It seems to me, then, either way, it's an issue of multithreading...whether
my way or Hilaire's way.
Sven Van Caekenberghe-2 wrote
> Hi Horrido,
>
> It is very hard to follow what you are exactly doing or trying to do.
>
> Here is the simplest example I can think of that updates something in
> Morphic on a regular basis.
>
> StringMorph subclass: #MyClock
> instanceVariableNames: ''
> classVariableNames: ''
> package: '_UnpackagedPackage'
>
> MyClock>>#initialize
> super initialize.
> self updateClock
>
> MyClock>>#step
> self updateClock
>
> MyClock>>#updateClock
> self contents: Time now printString
>
> MyClock class>>#open
> "self open"
>
> ^ self new openInWindow
>
> This inherits #stepTime as 1 second. If I open such a window and save my
> image, it is still there when the image is restarted, with the clock still
> working.
>
> Updating (data structures in) the main UI process from another process is
> dangerous. Saving such constructs is even more dangerous.
>
> HTH,
>
> Sven
>
>> On 2 Jun 2017, at 15:54, horrido <
> horrido.hobbies@
> > wrote:
>>
>> Sorry, I could be mistaken. I just checked my notes. The *0 asString*
>> test
>> failed once, but I've not been able to replicate it. I might've been
>> working
>> with an unclean image.
>>
>> So perhaps it is related to Morphic, after all.
>>
>>
>> horrido wrote
>>> Yup, they all fail. Interesting that
>> *
>>> 0 asString
>> *
>>> fails. This means it has NOTHING to do with Morphic (or Morphic being
>>> thread-unsafe).
>>>
>>> Ben Coman wrote
>>>> On Wed, May 31, 2017 at 10:23 PM, horrido <
>>
>>>> horrido.hobbies@
>>
>>>> > wrote:
>>>>
>>>> Can you try a few other variations...
>>>> [ [ true ] whileTrue: [ 0 asString. delay wait ] fork.
>>>> [ [ true ] whileTrue: [ a contents: '0'. delay wait ] fork.
>>>> [ [ true ] whileTrue: [ a contents: '0'. ] forkAt: 20.
>>>>
>>>> cheers -ben
>>
>>
>>
>>
>>
>> --
>> View this message in context:
>> http://forum.world.st/Morphic-or-forking-bug-tp4948727p4948984.html
>> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
--
View this message in context: http://forum.world.st/Morphic-or-forking-bug-tp4948727p4949166.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 3, 2017
Re: [Pharo-users] planet squeak and friends
by Bruce O'Neel
Hi Stef,
Thanks.ÃÂ Do you mind that planet squeak has Pharo blogs?ÃÂ I think it's reasonable since they share a history.
cheers
bruce
June 3, 2017
Deprecating Auto-fix: WOW
by Sean P. DeNigris
Either I died and went to heaven, or my Pharo 6 image just ported all my
deprecated methods auto-magically. Very cool! Thanks!!!
-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/Deprecating-Auto-fix-WOW-tp4949164.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 3, 2017
Re: [Pharo-users] Pharo and QT
by Julien Delplanque
Hello,
Some month ago I did a project that allows to generate python code from
Pharo, Python3Generator [1].
I used it to play with Matplotlib [2] and it works pretty well (I should
announce these projects one day... :-) ).
Seeing your mail, I took a look at it to see if it was possible to make
a PyQt windows
pop using it and it works (I'll put the source code to try by yourself
at the end of this mail).
Of course, once you start Qt events loop, the image is frozen (see the
screenshot attached to this mail). :-)
Nevertheless, P3G is not complete and yet, you can not retrieve values
from Python side, it is just
used to generate and execute code without getting results back from an
execution. I guess this
will be problematic for buttons callbacks for example. But it could
probably be extended to retrieve
these values...
P3G can use your Atlas Python interpreter but, I could not get a window
to pop with it. I don't know
why since the interpreter returns no error.
Julien
Links:
[1]: https://github.com/juliendelplanque/Python3Generator
[2]: https://github.com/juliendelplanque/MatplotLibBridge
Load P3G:
Metacello new
baseline: 'Python3Generator';
repository: 'github://juliendelplanque/Python3Generator/repository';
load
The source code (#<- message is used to build an assignation, #=> is
used to access the attribute of an object):
"Use and initialize the FFI interpreter."
P3GInterpreter useFFIInterpreter.
P3GInterpreter current pathToPython: '/usr/bin/python3'.
"instructions will hold the instructions of the program we are going to
build."
instructions := P3GInstructionsList new.
"Import sys and PyQt."
sys := 'sys' asP3GIdentifier.
pyqt := 'PyQt4' asP3GIdentifier => 'QtGui'.
instructions
add: sys import;
add: pyqt import.
"Instantiate Qt App."
app := 'app' asP3GIdentifier.
instructions
add: app <- ((pyqt => 'QApplication') callWith: #(())).
"Create a simple window with a progress bar."
w := 'w' asP3GIdentifier.
instructions
add: w <- (pyqt => 'QMainWindow') call;
add: (((w => 'statusBar') call => 'showMessage') callWith: #('Ready'));
add: ((w => 'setGeometry') callWith: #(300 300 250 150));
add: (( w => 'setWindowTitle') callWith: #(Statusbar));
add: (w => 'show') call;
add: ((sys => 'exit') callWith: { (app => 'exec_') call }).
"Execute the program built (you can inspect instructions to see the
source code)."
instructions execute.
On 02/06/17 22:00, Dimitris Chloupis wrote:
> There is a way to make this into a small task
>
> One of my experiments of testing my Pharo to Python bridge (What I have
> named project "Atlas") was to build a QT hello world example. It created a
> problem because I was using python threads that QT does not like (it offers
> its own kind of threads) but after changing the code to use no threads, it
> worked.
>
> My bridge is not like UFFI where anything has to be wrapped because unlike
> C , Python is a dynamic language so there is no need for wrappers because
> Atlas allows dynamic execution of code. But of course there is the issues
> of data types and how they can be mapped to Pharo and the fact that PyQT
> free version is GPL and commercial is 500 dollars which sits of course on
> top of the commercial version of QT. So at the time I decided to not pursue
> it.
>
> I will give it a try and see how far it can goes, at worst I may offer a
> partial solution to using QT with Pharo. Then someone else can take it from
> there if there is genuine interest and expand it to more features.
>
> On Fri, Jun 2, 2017 at 12:01 AM Stephane Ducasse <stepharo.self(a)gmail.com>
> wrote:
>
>> Hi dimitris
>>
>> We would love to have that. We could have a Spec binding and build
>> automatically applications in QT for people willing.
>> Esteban always wanted to have a Cocoa binding used the same way.
>> But this is large task
>>
>> Stef
>>
>> On Thu, Jun 1, 2017 at 2:44 PM, Hilaire <hilaire(a)drgeo.eu> wrote:
>>
>>> A must for any serious dekstop application with Pharo, but it is a hudge
>>> task
>>>
>>>
>>> Le 29/05/2017 à 14:35, Dimitris Chloupis a écrit :
>>>> Is there an interest for working with QT from Pharo ? I make no
>>>> promises just something I was interested in trying.
>>> --
>>> Dr. Geo
>>> http://drgeo.eu
>>>
>>>
>>>
>>>
June 3, 2017
Re: [Pharo-users] planet squeak and friends
by Stephane Ducasse
Hi Bruce
Thanks for taking care about this.
Now I would check because there are many broken old links and it gives the
impression of abandonware.
Pharo official blog is: https://pharoweekly.wordpress.com
and it points to three blogs:
- http://astares.blogspot.fr (excellent and active)
- https://clementbera.wordpress.com (really nice to understand inside
the vm).
- and cog
Stef
On Sat, Jun 3, 2017 at 11:00 AM, Bruce O'Neel <bruce.oneel(a)pckswarms.ch>
wrote:
> Hi,
>
> At a timescale that only can be described as geological I am moving the
> existing planet squeak and friends http://planet.squeak.org/ to a new box
> and will be maintaining it.
>
> Lots of the links have rotted over time. If you have a squeak or pharo
> related blog could you glance at the links on the right hand side of
> planet.squeak.org and see if your blog is listed, and, if so make sure
> the feed link is ok? If it is not listed if you send me the info I will
> add it.
>
> Finally, does someone have an opinion about what to do with Andreas'
> blog? I would like to leave it... And what about the others that are no
> longer updated but still work?
>
> cheers
>
> bruce
>
>
>
June 3, 2017
planet squeak and friends
by Bruce O'Neel
Hi,
At a timescale that only can be described as geological I am moving the existing planet squeak and friends [http://planet.squeak.org/](http://planet.squeak.org/) to a new box and will be maintaining it.
Lots of the links have rotted over time.ÃÂ If you have a squeak or pharo related blog could you glance at the links on the right hand side of planet.squeak.org and see if your blog is listed, and, if so make sure the feed link is ok?ÃÂ If it is not listed if you send me the info I will add it.
Finally, does someone have an opinion about what to do with Andreas' blog?ÃÂ I would like to leave it...ÃÂ And what about the others that are no longer updated but still work?
cheers
bruce
June 3, 2017
Re: [Pharo-users] [Deploy] Deploying application - New Best Practices?
by Pierce Ng
On Fri, Jun 02, 2017 at 12:52:35PM -0700, sergio_101 wrote:
> Where can i find a current RFBServer?
http://smalltalkhub.com/#!/~PharoExtras/RFB
June 3, 2017
Re: [Pharo-users] Pharo and QT
by Pieter Swinkels
One other thing, what part of Qt you would like to use, the widget world or the QML world?
I have been thinking about building a UI in QML and using Pharo to implement the model. This could be doable. However, the best idea I came up with (up till now) would require custom glue code in C++ (although I do like the idea of integrating with PyQt or PySide instead). But I have only been toying with the idea, nothing more.
I intended to post the message to the mailing list before, but by accident I sent it directly to another mailing list participant. My sincere apologies for that...
Kind regards, Pieter.
On Friday, June 2, 2017 10:02 PM, Dimitris Chloupis <kilon.alios(a)gmail.com> wrote:
There is a way to make this into a small task
One of my experiments of testing my Pharo to Python bridge (What I have named project "Atlas") was to  build a QT hello world example. It created a problem because I was using python threads that QT does not like (it offers its own kind of threads) but after changing the code to use no threads, it worked.Â
My bridge is not like UFFI where anything has to be wrapped because unlike C , Python is a dynamic language so there is no need for wrappers because Atlas allows dynamic execution of code. But of course there is the issues of data types and how they can be mapped to Pharo and the fact that PyQT free version is GPL and commercial is 500 dollars which sits of course on top of the commercial version of QT. So at the time I decided to not pursue it.Â
I will give it a try and see how far it can goes, at worst I may offer a partial solution to using QT with Pharo. Then someone else can take it from there if there is genuine interest and expand it to more features. Â
June 3, 2017
Re: [Pharo-users] Pharo and QT
by Pieter Swinkels
With regard toÂ
>> the fact that PyQT free version is GPL and commercial is 500 dollars which sits of course on top of the commercial version of QTÂ
There is an alternative to PyQt, that the Qt company intends to make a first-class citizen of the Qt ecosystem, namely PySide(2). The project languished after Nokia sold Qt to what is know "The Qt Company", but development is ongoing again. For details, see https://wiki.qt.io/PySide2 and https://groups.google.com/d/msg/pyside-dev/pqwzngAGLWE/kXUpXBhILAAJ For the record, I do not use PySide (or PyQt for that matter) and I do not know what the current status is of this endeavor.
Kind regards, Pieter.
On Friday, June 2, 2017 10:02 PM, Dimitris Chloupis <kilon.alios(a)gmail.com> wrote:
There is a way to make this into a small task
One of my experiments of testing my Pharo to Python bridge (What I have named project "Atlas") was to  build a QT hello world example. It created a problem because I was using python threads that QT does not like (it offers its own kind of threads) but after changing the code to use no threads, it worked.Â
My bridge is not like UFFI where anything has to be wrapped because unlike C , Python is a dynamic language so there is no need for wrappers because Atlas allows dynamic execution of code. But of course there is the issues of data types and how they can be mapped to Pharo and the fact that PyQT free version is GPL and commercial is 500 dollars which sits of course on top of the commercial version of QT. So at the time I decided to not pursue it.Â
I will give it a try and see how far it can goes, at worst I may offer a partial solution to using QT with Pharo. Then someone else can take it from there if there is genuine interest and expand it to more features. Â
On Fri, Jun 2, 2017 at 12:01 AM Stephane Ducasse <stepharo.self(a)gmail.com> wrote:
Hi dimitris
We would love to have that. We could have a Spec binding and build automatically applications in QT for people willing. Esteban always wanted to have a Cocoa binding used the same way. But this is large task
Stef
On Thu, Jun 1, 2017 at 2:44 PM, Hilaire <hilaire(a)drgeo.eu> wrote:
A must for any serious dekstop application with Pharo, but it is a hudge
task
Le 29/05/2017 à 14:35, Dimitris Chloupis a écrit :
> Is there an interest for working with QT from Pharo ? I make no
> promises just something I was interested in trying.
--
Dr. Geo
http://drgeo.eu
June 3, 2017
Re: [Pharo-users] Pharo and QT
by Ben Coman
As long as your having fun yourself, sounds like a good idea. If you
manage a minimum viable product like example code, wider interest may
arise. Good luck.
cheers -ben
On Sat, Jun 3, 2017 at 4:00 AM, Dimitris Chloupis <kilon.alios(a)gmail.com>
wrote:
> There is a way to make this into a small task
>
> One of my experiments of testing my Pharo to Python bridge (What I have
> named project "Atlas") was to build a QT hello world example. It created a
> problem because I was using python threads that QT does not like (it offers
> its own kind of threads) but after changing the code to use no threads, it
> worked.
>
> My bridge is not like UFFI where anything has to be wrapped because unlike
> C , Python is a dynamic language so there is no need for wrappers because
> Atlas allows dynamic execution of code. But of course there is the issues
> of data types and how they can be mapped to Pharo and the fact that PyQT
> free version is GPL and commercial is 500 dollars which sits of course on
> top of the commercial version of QT. So at the time I decided to not pursue
> it.
>
> I will give it a try and see how far it can goes, at worst I may offer a
> partial solution to using QT with Pharo. Then someone else can take it from
> there if there is genuine interest and expand it to more features.
>
> On Fri, Jun 2, 2017 at 12:01 AM Stephane Ducasse <stepharo.self(a)gmail.com>
> wrote:
>
>> Hi dimitris
>>
>> We would love to have that. We could have a Spec binding and build
>> automatically applications in QT for people willing.
>> Esteban always wanted to have a Cocoa binding used the same way.
>> But this is large task
>>
>> Stef
>>
>> On Thu, Jun 1, 2017 at 2:44 PM, Hilaire <hilaire(a)drgeo.eu> wrote:
>>
>>> A must for any serious dekstop application with Pharo, but it is a hudge
>>> task
>>>
>>>
>>> Le 29/05/2017 à 14:35, Dimitris Chloupis a écrit :
>>> > Is there an interest for working with QT from Pharo ? I make no
>>> > promises just something I was interested in trying.
>>>
>>> --
>>> Dr. Geo
>>> http://drgeo.eu
>>>
>>>
>>>
>>>
>>
June 3, 2017
Analyzing Fuel Problem
by Sean P. DeNigris
I had an object graph that was pulling in all sorts of unrelated classes when
serialized with Fuel. I was trying to find the offending object, and came up
with the following:
```
(FLAnalyzer newDefault analysisFor: root) clusterization globalsBucket
```
This worked, but I was wondering if that's "the right way" to do it...
Thanks.
-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/Analyzing-Fuel-Problem-tp4949104.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 3, 2017
Re: [Pharo-users] Deprecation Warning
by Bernardo Ezequiel Contreras
World>>System>>Settings
Tools>>Debugging>>Deprecation handling
Raise a blocking dialog
if true, then a dialog is popup for each deprecated method invocation
hth
On Fri, Jun 2, 2017 at 7:28 PM, Georges <gkgobith(a)gmail.com> wrote:
> Hello,
>
> Is there somewhere a setting to turn off the Deprecation Warning debugger?
>
> Georges
>
>
>
> --
> View this message in context: http://forum.world.st/
> Deprecation-Warning-tp4949096.html
> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>
>
--
Bernardo E.C.
Sent from a cheap desktop computer in South America.
June 2, 2017
Re: [Pharo-users] Deprecation Warning
by Georges
Thanks !
--
View this message in context: http://forum.world.st/Deprecation-Warning-tp4949096p4949098.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 2, 2017
Deprecation Warning
by Georges
Hello,
Is there somewhere a setting to turn off the Deprecation Warning debugger?
Georges
--
View this message in context: http://forum.world.st/Deprecation-Warning-tp4949096.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 2, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Steffen Märcker
Thanks, this appears to work. Attached you'll find the file-out from
VisualWorks and the file-out from Pharo (includes package comment).
Cheers!
Steffen
Am .06.2017, 20:06 Uhr, schrieb Yanni Chiu <yanni.code(a)gmail.com>:
> To get the extension methods into the Transducers package, the following
> worked for me - edit the category to have the prefix '*Transducers-'
>
> 2710c2710
>
> < !Number methodsFor: 'transforming' stamp: ' 2/6/17 15:38'!
>
> ---
>
>> !Number methodsFor: '*Transducers-transforming' stamp: ' 2/6/17 15:38'!
>
>
> On Fri, Jun 2, 2017 at 11:05 AM, Steffen Märcker <merkste(a)web.de> wrote:
>
>> Dear all,
>>
>> thanks for the many suggestions. I didn't had time to test all
>> import/export ways yet. But for now, I can report on two:
>>
>> 1) NGFileOuter
>> Unfortunately It raised several MNUs in my image. I'll investigate them
>> later.
>>
>> 2) FileOut30 (VW Contributed)
>> I was able to file out the code except for the package definition.
>> Replacing {category: ''} in the class definitions with {package:
>> 'Transducers'} fixed that. However, methods that extend existing classes
>> did not end up in the Transducers package. Is there a similar easy
>> change
>> to the file-out making that happen? Also I'd like to add the package
>> comment if that's possible.
>>
>> Most things appear to work as far as I can see. Two exceptions:
>> 1) Random is a subclass of Stream in VW and in Pharo it is not. Hence,
>> I'll have to copy some methods from Stream to Random.
>> 2) I used #beImmutable in VW but I couldn't yet figure out how to make
>> objects immutable in Pharo.
>>
>> However, until the tests are ported, I cannot guarantee. Porting the
>> test
>> suite will be another beast, since I rely on the excellent
>> mocking/stubbing
>> library DoubleAgents by Randy Coulman. I am not sure how I will handle
>> that. In general, I think it would be really worth the effort to be
>> ported
>> to Pharo, too. DoubleAgents is pretty powerful and produces easy to read
>> and understand mocking/stubbing code. Personally, I prefer it clearly,
>> e.g., over Mocketry (no offence intended!).
>>
>> Attached you'll find the file-out that I loaded into Pharo. The issues
>> above are not addressed yet. However, the following example works:
>>
>> | scale sides count collect experiment random samples coin flip |
>> scale := [:x | (x * 2 + 1) floor] map.
>> sides := #(heads tails) replace.
>> count := 1000 take.
>> collect := [:bag :c | bag add: c; yourself].
>> experiment := (scale * sides * count) transform: collect.
>> random := #(0.1 0.3 0.4 0.5 0.6 0.7 0.8 0.9).
>>
>> samples := random
>> reduce: experiment
>> init: Bag new.
>>
>> samples := random
>> transduce: scale * sides * count
>> reduce: collect
>> init: Bag new.
>>
>> coin := sides <~ scale <~ random.
>> flip := Bag <~ count.
>>
>> samples := flip <~ coin.
>>
>>
>> Best, Steffen
>>
>>
>>
>> Am .06.2017, 08:16 Uhr, schrieb Stephane Ducasse
>> <stepharo.self(a)gmail.com
>> >:
>>
>> There is a package for that NGFileOuter or something like that on cincom
>>> store.
>>> We used it for mobydic code.
>>>
>>> On Wed, May 31, 2017 at 6:35 PM, Alexandre Bergel <
>>> alexandre.bergel(a)me.com>
>>> wrote:
>>>
>>> If I remember correctly, there is a parcel in VisualWorks to export a
>>> file
>>>> out (Squeak format).
>>>>
>>>> @Milton, can you give a hand to Steffen?
>>>>
>>>> Alexandre
>>>> --
>>>> _,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
>>>> Alexandre Bergel http://www.bergel.eu
>>>> ^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
>>>>
>>>>
>>>>
>>>> On May 31, 2017, at 10:32 AM, Steffen Märcker <merkste(a)web.de> wrote:
>>>>
>>>> Thanks for the encouraging response! First question: Which is the
>>>> recommended (friction free) way to exchange code between VW and Pharo?
>>>>
>>>> Cheers!
>>>> Steffen
>>>>
>>>> Am .05.2017, 16:22 Uhr, schrieb Alexandre Bergel <
>>>> alexandre.bergel(a)me.com
>>>> >:
>>>>
>>>> I second Sven. This is very exciting!
>>>>
>>>> Let us know when you have something ready to be tested.
>>>>
>>>> Alexandre
>>>>
>>>>
>>>>
>>>>
June 2, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Steffen Märcker
Hi Stephane & Damien!
The short answer is that the compact notation turned out to work much
better for me in my code, especially, if multiple transducers are
involved. But that's my personal taste. You can choose which suits you
better. In fact,
1000 take.
just sits on top and simply calls
Take number: 1000.
If the need arises, we could of course factor the compact notation out
into a separate package. Btw, would you prefer (Take n: 1000) over (Take
number: 1000)?
Damien, you're right, I experimented with additional styles. Right now, we
already have in the basic Transducer package:
(collection transduce: #squared map * 1000 take. "which is equal to"
(collection transduce: #squared map) transduce: 1000 take.
Basically, one can split #transduce:reduce:init: into single calls of
#transduce:, #reduce:, and #init:, depending on the needs.
I also have an (unfinished) extension, that allows to write:
(collection transduce map: #squared) take: 1000.
This feels familiar, but becomes a bit hard to read if more than two steps
are needed.
collection transduce
map: #squared;
take: 1000.
I think, this alternative would reads nicely. But as the message chain has
to modify the underlying object (an eduction), very snaky side effects may
occur. E.g., consider
eduction := collection transduce.
squared := eduction map: #squared.
take := squared take: 1000.
Now, all three variables hold onto the same object, which first squares
all elements and than takes the first 1000.
Best,
Steffen
Am .06.2017, 21:28 Uhr, schrieb Damien Pollet
<damien.pollet+pharo(a)gmail.com>:
> If I recall correctly, there is an alternate protocol that looks more
> like
> xtreams or the traditional select/collect iterations.
>
> On 2 June 2017 at 21:12, Stephane Ducasse <stepharo.self(a)gmail.com>
> wrote:
>
>> I have a design question
>>
>> why the library is implemented in functional style vs messages?
>> I do not see why this is needed. To my eyes the compact notation
>> goes against readibility of code and it feels ad-hoc in Smalltalk.
>>
>>
>> I really prefer
>>
>> square := Map function: #squared.
>> take := Take number: 1000.
>>
>> Because I know that I can read it and understand it.
>> From that perspective I prefer Xtreams.
>>
>> Stef
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> On Wed, May 31, 2017 at 2:23 PM, Steffen Märcker <merkste(a)web.de> wrote:
>>
>>> Hi,
>>>
>>> I am the developer of the library 'Transducers' for VisualWorks. It was
>>> formerly known as 'Reducers', but this name was a poor choice. I'd
>>> like to
>>> port it to Pharo, if there is any interest on your side. I hope to
>>> learn
>>> more about Pharo in this process, since I am mainly a VW guy. And most
>>> likely, I will come up with a bunch of questions. :-)
>>>
>>> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be
>>> very
>>> happy to hear your optinions, questions and I hope we can start a
>>> fruitful
>>> discussion - even if there is not Pharo port yet.
>>>
>>> Best, Steffen
>>>
>>>
>>>
>>> Transducers are building blocks that encapsulate how to process
>>> elements
>>> of a data sequence independently of the underlying input and output
>>> source.
>>>
>>>
>>>
>>> # Overview
>>>
>>> ## Encapsulate
>>> Implementations of enumeration methods, such as #collect:, have the
>>> logic
>>> how to process a single element in common.
>>> However, that logic is reimplemented each and every time. Transducers
>>> make
>>> it explicit and facilitate re-use and coherent behavior.
>>> For example:
>>> - #collect: requires mapping: (aBlock1 map)
>>> - #select: requires filtering: (aBlock2 filter)
>>>
>>>
>>> ## Compose
>>> In practice, algorithms often require multiple processing steps, e.g.,
>>> mapping only a filtered set of elements.
>>> Transducers are inherently composable, and hereby, allow to make the
>>> combination of steps explicit.
>>> Since transducers do not build intermediate collections, their
>>> composition
>>> is memory-efficient.
>>> For example:
>>> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map
>>> elements"
>>>
>>>
>>> ## Re-Use
>>> Transducers are decoupled from the input and output sources, and hence,
>>> they can be reused in different contexts.
>>> For example:
>>> - enumeration of collections
>>> - processing of streams
>>> - communicating via channels
>>>
>>>
>>>
>>> # Usage by Example
>>>
>>> We build a coin flipping experiment and count the occurrence of heads
>>> and
>>> tails.
>>>
>>> First, we associate random numbers with the sides of a coin.
>>>
>>> scale := [:x | (x * 2 + 1) floor] map.
>>> sides := #(heads tails) replace.
>>>
>>> Scale is a transducer that maps numbers x between 0 and 1 to 1 and 2.
>>> Sides is a transducer that replaces the numbers with heads an tails by
>>> lookup in an array.
>>> Next, we choose a number of samples.
>>>
>>> count := 1000 take.
>>>
>>> Count is a transducer that takes 1000 elements from a source.
>>> We keep track of the occurrences of heads an tails using a bag.
>>>
>>> collect := [:bag :c | bag add: c; yourself].
>>>
>>> Collect is binary block (reducing function) that collects events in a
>>> bag.
>>> We assemble the experiment by transforming the block using the
>>> transducers.
>>>
>>> experiment := (scale * sides * count) transform: collect.
>>>
>>> From left to right we see the steps involved: scale, sides, count and
>>> collect.
>>> Transforming assembles these steps into a binary block (reducing
>>> function)
>>> we can use to run the experiment.
>>>
>>> samples := Random new
>>> reduce: experiment
>>> init: Bag new.
>>>
>>> Here, we use #reduce:init:, which is mostly similar to #inject:into:.
>>> To execute a transformation and a reduction together, we can use
>>> #transduce:reduce:init:.
>>>
>>> samples := Random new
>>> transduce: scale * sides * count
>>> reduce: collect
>>> init: Bag new.
>>>
>>> We can also express the experiment as data-flow using #<~.
>>> This enables us to build objects that can be re-used in other
>>> experiments.
>>>
>>> coin := sides <~ scale <~ Random new.
>>> flip := Bag <~ count.
>>>
>>> Coin is an eduction, i.e., it binds transducers to a source and
>>> understands #reduce:init: among others.
>>> Flip is a transformed reduction, i.e., it binds transducers to a
>>> reducing
>>> function and an initial value.
>>> By sending #<~, we draw further samples from flipping the coin.
>>>
>>> samples := flip <~ coin.
>>>
>>> This yields a new Bag with another 1000 samples.
>>>
>>>
>>>
>>> # Basic Concepts
>>>
>>> ## Reducing Functions
>>>
>>> A reducing function represents a single step in processing a data
>>> sequence.
>>> It takes an accumulated result and a value, and returns a new
>>> accumulated
>>> result.
>>> For example:
>>>
>>> collect := [:col :e | col add: e; yourself].
>>> sum := #+.
>>>
>>> A reducing function can also be ternary, i.e., it takes an accumulated
>>> result, a key and a value.
>>> For example:
>>>
>>> collect := [:dic :k :v | dict at: k put: v; yourself].
>>>
>>> Reducing functions may be equipped with an optional completing action.
>>> After finishing processing, it is invoked exactly once, e.g., to free
>>> resources.
>>>
>>> stream := [:str :e | str nextPut: each; yourself] completing:
>>> #close.
>>> absSum := #+ completing: #abs
>>>
>>> A reducing function can end processing early by signaling Reduced with
>>> a
>>> result.
>>> This mechanism also enables the treatment of infinite sources.
>>>
>>> nonNil := [:res :e | e ifNil: [Reduced signalWith: res] ifFalse:
>>> [res]].
>>>
>>> The primary approach to process a data sequence is the reducing
>>> protocol
>>> with the messages #reduce:init: and #transduce:reduce:init: if
>>> transducers
>>> are involved.
>>> The behavior is similar to #inject:into: but in addition it takes care
>>> of:
>>> - handling binary and ternary reducing functions,
>>> - invoking the completing action after finishing, and
>>> - stopping the reduction if Reduced is signaled.
>>> The message #transduce:reduce:init: just combines the transformation
>>> and
>>> the reducing step.
>>>
>>> However, as reducing functions are step-wise in nature, an application
>>> may
>>> choose other means to process its data.
>>>
>>>
>>> ## Reducibles
>>>
>>> A data source is called reducible if it implements the reducing
>>> protocol.
>>> Default implementations are provided for collections and streams.
>>> Additionally, blocks without an argument are reducible, too.
>>> This allows to adapt to custom data sources without additional effort.
>>> For example:
>>>
>>> "XStreams adaptor"
>>> xstream := filename reading.
>>> reducible := [[xstream get] on: Incomplete do: [Reduced signal]].
>>>
>>> "natural numbers"
>>> n := 0.
>>> reducible := [n := n+1].
>>>
>>>
>>> ## Transducers
>>>
>>> A transducer is an object that transforms a reducing function into
>>> another.
>>> Transducers encapsulate common steps in processing data sequences,
>>> such as
>>> map, filter, concatenate, and flatten.
>>> A transducer transforms a reducing function into another via
>>> #transform:
>>> in order to add those steps.
>>> They can be composed using #* which yields a new transducer that does
>>> both
>>> transformations.
>>> Most transducers require an argument, typically blocks, symbols or
>>> numbers:
>>>
>>> square := Map function: #squared.
>>> take := Take number: 1000.
>>>
>>> To facilitate compact notation, the argument types implement
>>> corresponding
>>> methods:
>>>
>>> squareAndTake := #squared map * 1000 take.
>>>
>>> Transducers requiring no argument are singletons and can be accessed by
>>> their class name.
>>>
>>> flattenAndDedupe := Flatten * Dedupe.
>>>
>>>
>>>
>>> # Advanced Concepts
>>>
>>> ## Data flows
>>>
>>> Processing a sequence of data can often be regarded as a data flow.
>>> The operator #<~ allows define a flow from a data source through
>>> processing steps to a drain.
>>> For example:
>>>
>>> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
>>> fileOut writeStream <~ #isSeparator filter <~ fileIn readStream.
>>>
>>> In both examples #<~ is only used to set up the data flow using
>>> reducing
>>> functions and transducers.
>>> In contrast to streams, transducers are completely independent from
>>> input
>>> and output sources.
>>> Hence, we have a clear separation of reading data, writing data and
>>> processing elements.
>>> - Sources know how to iterate over data with a reducing function, e.g.,
>>> via #reduce:init:.
>>> - Drains know how to collect data using a reducing function.
>>> - Transducers know how to process single elements.
>>>
>>>
>>> ## Reductions
>>>
>>> A reduction binds an initial value or a block yielding an initial
>>> value to
>>> a reducing function.
>>> The idea is to define a ready-to-use process that can be applied in
>>> different contexts.
>>> Reducibles handle reductions via #reduce: and #transduce:reduce:
>>> For example:
>>>
>>> sum := #+ init: 0.
>>> sum1 := #(1 1 1) reduce: sum.
>>> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
>>>
>>> asSet := [:set :e | set add: e; yourself] initializer: [Set new].
>>> set1 := #(1 1 1) reduce: asSet.
>>> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
>>>
>>> By combining a transducer with a reduction, a process can be further
>>> modified.
>>>
>>> sumOdds := sum <~ #odd filter
>>> setOdds := asSet <~ #odd filter
>>>
>>>
>>> ## Eductions
>>>
>>> An eduction combines a reducible data sources with a transducer.
>>> The idea is to define a transformed (virtual) data source that needs
>>> not
>>> to be stored in memory.
>>>
>>> odds1 := #odd filter <~ #(1 2 3) readStream.
>>> odds2 := #odd filter <~ (1 to 1000).
>>>
>>> Depending on the underlying source, eductions can be processed once
>>> (streams, e.g., odds1) or multiple times (collections, e.g., odds2).
>>> Since no intermediate data is stored, transducers actions are lazy,
>>> i.e.,
>>> they are invoked each time the eduction is processed.
>>>
>>>
>>>
>>> # Origins
>>>
>>> Transducers is based on the same-named Clojure library and its ideas.
>>> Please see:
>>> http://clojure.org/transducers
>>>
>>>
June 2, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Steffen Märcker
Hi Stephane!
> This is a great news. We need cool frameworks.
I am really curious how well it will work for others. =)
> - There is a package on cincom store to support the migration from VW to
> Pharo. FileOuter something. The name escapes my mind now. We updated it
> last year to help porting one application to Pharo.
I think it is FileOuterNG (at least your name appears quit often in the
commits ;-) ).
Unfortunately, I didn't get it to work straight away and got some MNU. But
it it is very likely, that this is my fault and I missed something
important. I'll try it again later.
> - I can help producing a nice document :)
Do you mean like the booklets published over the last weeks? This would be
great.
Do you have an idea, how to add a package comment to the simple file-out
it used? I think, a simple message send should suffice.
Cheers!
Steffen
Am .06.2017, 21:06 Uhr, schrieb Stephane Ducasse <stepharo.self(a)gmail.com>:
> Hi steffen
>
>
> On Wed, May 31, 2017 at 2:23 PM, Steffen Märcker <merkste(a)web.de> wrote:
>
>> Hi,
>>
>> I am the developer of the library 'Transducers' for VisualWorks. It was
>> formerly known as 'Reducers', but this name was a poor choice. I'd like
>> to
>> port it to Pharo, if there is any interest on your side. I hope to learn
>> more about Pharo in this process, since I am mainly a VW guy. And most
>> likely, I will come up with a bunch of questions. :-)
>>
>> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be very
>> happy to hear your optinions, questions and I hope we can start a
>> fruitful
>> discussion - even if there is not Pharo port yet.
>>
>> Best, Steffen
>>
>>
>>
>> Transducers are building blocks that encapsulate how to process elements
>> of a data sequence independently of the underlying input and output
>> source.
>>
>>
>>
>> # Overview
>>
>> ## Encapsulate
>> Implementations of enumeration methods, such as #collect:, have the
>> logic
>> how to process a single element in common.
>> However, that logic is reimplemented each and every time. Transducers
>> make
>> it explicit and facilitate re-use and coherent behavior.
>> For example:
>> - #collect: requires mapping: (aBlock1 map)
>> - #select: requires filtering: (aBlock2 filter)
>>
>>
>> ## Compose
>> In practice, algorithms often require multiple processing steps, e.g.,
>> mapping only a filtered set of elements.
>> Transducers are inherently composable, and hereby, allow to make the
>> combination of steps explicit.
>> Since transducers do not build intermediate collections, their
>> composition
>> is memory-efficient.
>> For example:
>> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map elements"
>>
>>
>> ## Re-Use
>> Transducers are decoupled from the input and output sources, and hence,
>> they can be reused in different contexts.
>> For example:
>> - enumeration of collections
>> - processing of streams
>> - communicating via channels
>>
>>
>>
>> # Usage by Example
>>
>> We build a coin flipping experiment and count the occurrence of heads
>> and
>> tails.
>>
>> First, we associate random numbers with the sides of a coin.
>>
>> scale := [:x | (x * 2 + 1) floor] map.
>> sides := #(heads tails) replace.
>>
>> Scale is a transducer that maps numbers x between 0 and 1 to 1 and 2.
>> Sides is a transducer that replaces the numbers with heads an tails by
>> lookup in an array.
>> Next, we choose a number of samples.
>>
>> count := 1000 take.
>>
>> Count is a transducer that takes 1000 elements from a source.
>> We keep track of the occurrences of heads an tails using a bag.
>>
>> collect := [:bag :c | bag add: c; yourself].
>>
>> Collect is binary block (reducing function) that collects events in a
>> bag.
>> We assemble the experiment by transforming the block using the
>> transducers.
>>
>> experiment := (scale * sides * count) transform: collect.
>>
>> From left to right we see the steps involved: scale, sides, count and
>> collect.
>> Transforming assembles these steps into a binary block (reducing
>> function)
>> we can use to run the experiment.
>>
>> samples := Random new
>> reduce: experiment
>> init: Bag new.
>>
>> Here, we use #reduce:init:, which is mostly similar to #inject:into:.
>> To execute a transformation and a reduction together, we can use
>> #transduce:reduce:init:.
>>
>> samples := Random new
>> transduce: scale * sides * count
>> reduce: collect
>> init: Bag new.
>>
>> We can also express the experiment as data-flow using #<~.
>> This enables us to build objects that can be re-used in other
>> experiments.
>>
>> coin := sides <~ scale <~ Random new.
>> flip := Bag <~ count.
>>
>> Coin is an eduction, i.e., it binds transducers to a source and
>> understands #reduce:init: among others.
>> Flip is a transformed reduction, i.e., it binds transducers to a
>> reducing
>> function and an initial value.
>> By sending #<~, we draw further samples from flipping the coin.
>>
>> samples := flip <~ coin.
>>
>> This yields a new Bag with another 1000 samples.
>>
>>
>>
>> # Basic Concepts
>>
>> ## Reducing Functions
>>
>> A reducing function represents a single step in processing a data
>> sequence.
>> It takes an accumulated result and a value, and returns a new
>> accumulated
>> result.
>> For example:
>>
>> collect := [:col :e | col add: e; yourself].
>> sum := #+.
>>
>> A reducing function can also be ternary, i.e., it takes an accumulated
>> result, a key and a value.
>> For example:
>>
>> collect := [:dic :k :v | dict at: k put: v; yourself].
>>
>> Reducing functions may be equipped with an optional completing action.
>> After finishing processing, it is invoked exactly once, e.g., to free
>> resources.
>>
>> stream := [:str :e | str nextPut: each; yourself] completing:
>> #close.
>> absSum := #+ completing: #abs
>>
>> A reducing function can end processing early by signaling Reduced with a
>> result.
>> This mechanism also enables the treatment of infinite sources.
>>
>> nonNil := [:res :e | e ifNil: [Reduced signalWith: res] ifFalse:
>> [res]].
>>
>> The primary approach to process a data sequence is the reducing protocol
>> with the messages #reduce:init: and #transduce:reduce:init: if
>> transducers
>> are involved.
>> The behavior is similar to #inject:into: but in addition it takes care
>> of:
>> - handling binary and ternary reducing functions,
>> - invoking the completing action after finishing, and
>> - stopping the reduction if Reduced is signaled.
>> The message #transduce:reduce:init: just combines the transformation and
>> the reducing step.
>>
>> However, as reducing functions are step-wise in nature, an application
>> may
>> choose other means to process its data.
>>
>>
>> ## Reducibles
>>
>> A data source is called reducible if it implements the reducing
>> protocol.
>> Default implementations are provided for collections and streams.
>> Additionally, blocks without an argument are reducible, too.
>> This allows to adapt to custom data sources without additional effort.
>> For example:
>>
>> "XStreams adaptor"
>> xstream := filename reading.
>> reducible := [[xstream get] on: Incomplete do: [Reduced signal]].
>>
>> "natural numbers"
>> n := 0.
>> reducible := [n := n+1].
>>
>>
>> ## Transducers
>>
>> A transducer is an object that transforms a reducing function into
>> another.
>> Transducers encapsulate common steps in processing data sequences, such
>> as
>> map, filter, concatenate, and flatten.
>> A transducer transforms a reducing function into another via #transform:
>> in order to add those steps.
>> They can be composed using #* which yields a new transducer that does
>> both
>> transformations.
>> Most transducers require an argument, typically blocks, symbols or
>> numbers:
>>
>> square := Map function: #squared.
>> take := Take number: 1000.
>>
>> To facilitate compact notation, the argument types implement
>> corresponding
>> methods:
>>
>> squareAndTake := #squared map * 1000 take.
>>
>> Transducers requiring no argument are singletons and can be accessed by
>> their class name.
>>
>> flattenAndDedupe := Flatten * Dedupe.
>>
>>
>>
>> # Advanced Concepts
>>
>> ## Data flows
>>
>> Processing a sequence of data can often be regarded as a data flow.
>> The operator #<~ allows define a flow from a data source through
>> processing steps to a drain.
>> For example:
>>
>> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
>> fileOut writeStream <~ #isSeparator filter <~ fileIn readStream.
>>
>> In both examples #<~ is only used to set up the data flow using reducing
>> functions and transducers.
>> In contrast to streams, transducers are completely independent from
>> input
>> and output sources.
>> Hence, we have a clear separation of reading data, writing data and
>> processing elements.
>> - Sources know how to iterate over data with a reducing function, e.g.,
>> via #reduce:init:.
>> - Drains know how to collect data using a reducing function.
>> - Transducers know how to process single elements.
>>
>>
>> ## Reductions
>>
>> A reduction binds an initial value or a block yielding an initial value
>> to
>> a reducing function.
>> The idea is to define a ready-to-use process that can be applied in
>> different contexts.
>> Reducibles handle reductions via #reduce: and #transduce:reduce:
>> For example:
>>
>> sum := #+ init: 0.
>> sum1 := #(1 1 1) reduce: sum.
>> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
>>
>> asSet := [:set :e | set add: e; yourself] initializer: [Set new].
>> set1 := #(1 1 1) reduce: asSet.
>> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
>>
>> By combining a transducer with a reduction, a process can be further
>> modified.
>>
>> sumOdds := sum <~ #odd filter
>> setOdds := asSet <~ #odd filter
>>
>>
>> ## Eductions
>>
>> An eduction combines a reducible data sources with a transducer.
>> The idea is to define a transformed (virtual) data source that needs not
>> to be stored in memory.
>>
>> odds1 := #odd filter <~ #(1 2 3) readStream.
>> odds2 := #odd filter <~ (1 to 1000).
>>
>> Depending on the underlying source, eductions can be processed once
>> (streams, e.g., odds1) or multiple times (collections, e.g., odds2).
>> Since no intermediate data is stored, transducers actions are lazy,
>> i.e.,
>> they are invoked each time the eduction is processed.
>>
>>
>>
>> # Origins
>>
>> Transducers is based on the same-named Clojure library and its ideas.
>> Please see:
>> http://clojure.org/transducers
>>
June 2, 2017
Re: [Pharo-users] Pharo and QT
by Dimitris Chloupis
There is a way to make this into a small task
One of my experiments of testing my Pharo to Python bridge (What I have
named project "Atlas") was to build a QT hello world example. It created a
problem because I was using python threads that QT does not like (it offers
its own kind of threads) but after changing the code to use no threads, it
worked.
My bridge is not like UFFI where anything has to be wrapped because unlike
C , Python is a dynamic language so there is no need for wrappers because
Atlas allows dynamic execution of code. But of course there is the issues
of data types and how they can be mapped to Pharo and the fact that PyQT
free version is GPL and commercial is 500 dollars which sits of course on
top of the commercial version of QT. So at the time I decided to not pursue
it.
I will give it a try and see how far it can goes, at worst I may offer a
partial solution to using QT with Pharo. Then someone else can take it from
there if there is genuine interest and expand it to more features.
On Fri, Jun 2, 2017 at 12:01 AM Stephane Ducasse <stepharo.self(a)gmail.com>
wrote:
> Hi dimitris
>
> We would love to have that. We could have a Spec binding and build
> automatically applications in QT for people willing.
> Esteban always wanted to have a Cocoa binding used the same way.
> But this is large task
>
> Stef
>
> On Thu, Jun 1, 2017 at 2:44 PM, Hilaire <hilaire(a)drgeo.eu> wrote:
>
>> A must for any serious dekstop application with Pharo, but it is a hudge
>> task
>>
>>
>> Le 29/05/2017 à 14:35, Dimitris Chloupis a écrit :
>> > Is there an interest for working with QT from Pharo ? I make no
>> > promises just something I was interested in trying.
>>
>> --
>> Dr. Geo
>> http://drgeo.eu
>>
>>
>>
>>
>
June 2, 2017
Re: [Pharo-users] [Deploy] Deploying application - New Best Practices?
by sergio_101
Where can i find a current RFBServer?
Right now, I don't want to blow away what's currently running as it is an
image with data.. will figure out persistence later..
--
View this message in context: http://forum.world.st/Deploy-Deploying-application-New-Best-Practices-tp494…
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 2, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Damien Pollet
If I recall correctly, there is an alternate protocol that looks more like
xtreams or the traditional select/collect iterations.
On 2 June 2017 at 21:12, Stephane Ducasse <stepharo.self(a)gmail.com> wrote:
> I have a design question
>
> why the library is implemented in functional style vs messages?
> I do not see why this is needed. To my eyes the compact notation
> goes against readibility of code and it feels ad-hoc in Smalltalk.
>
>
> I really prefer
>
> square := Map function: #squared.
> take := Take number: 1000.
>
> Because I know that I can read it and understand it.
> From that perspective I prefer Xtreams.
>
> Stef
>
>
>
>
>
>
>
>
>
> On Wed, May 31, 2017 at 2:23 PM, Steffen Märcker <merkste(a)web.de> wrote:
>
>> Hi,
>>
>> I am the developer of the library 'Transducers' for VisualWorks. It was
>> formerly known as 'Reducers', but this name was a poor choice. I'd like to
>> port it to Pharo, if there is any interest on your side. I hope to learn
>> more about Pharo in this process, since I am mainly a VW guy. And most
>> likely, I will come up with a bunch of questions. :-)
>>
>> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be very
>> happy to hear your optinions, questions and I hope we can start a fruitful
>> discussion - even if there is not Pharo port yet.
>>
>> Best, Steffen
>>
>>
>>
>> Transducers are building blocks that encapsulate how to process elements
>> of a data sequence independently of the underlying input and output
>> source.
>>
>>
>>
>> # Overview
>>
>> ## Encapsulate
>> Implementations of enumeration methods, such as #collect:, have the logic
>> how to process a single element in common.
>> However, that logic is reimplemented each and every time. Transducers make
>> it explicit and facilitate re-use and coherent behavior.
>> For example:
>> - #collect: requires mapping: (aBlock1 map)
>> - #select: requires filtering: (aBlock2 filter)
>>
>>
>> ## Compose
>> In practice, algorithms often require multiple processing steps, e.g.,
>> mapping only a filtered set of elements.
>> Transducers are inherently composable, and hereby, allow to make the
>> combination of steps explicit.
>> Since transducers do not build intermediate collections, their composition
>> is memory-efficient.
>> For example:
>> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map elements"
>>
>>
>> ## Re-Use
>> Transducers are decoupled from the input and output sources, and hence,
>> they can be reused in different contexts.
>> For example:
>> - enumeration of collections
>> - processing of streams
>> - communicating via channels
>>
>>
>>
>> # Usage by Example
>>
>> We build a coin flipping experiment and count the occurrence of heads and
>> tails.
>>
>> First, we associate random numbers with the sides of a coin.
>>
>> scale := [:x | (x * 2 + 1) floor] map.
>> sides := #(heads tails) replace.
>>
>> Scale is a transducer that maps numbers x between 0 and 1 to 1 and 2.
>> Sides is a transducer that replaces the numbers with heads an tails by
>> lookup in an array.
>> Next, we choose a number of samples.
>>
>> count := 1000 take.
>>
>> Count is a transducer that takes 1000 elements from a source.
>> We keep track of the occurrences of heads an tails using a bag.
>>
>> collect := [:bag :c | bag add: c; yourself].
>>
>> Collect is binary block (reducing function) that collects events in a bag.
>> We assemble the experiment by transforming the block using the
>> transducers.
>>
>> experiment := (scale * sides * count) transform: collect.
>>
>> From left to right we see the steps involved: scale, sides, count and
>> collect.
>> Transforming assembles these steps into a binary block (reducing function)
>> we can use to run the experiment.
>>
>> samples := Random new
>> reduce: experiment
>> init: Bag new.
>>
>> Here, we use #reduce:init:, which is mostly similar to #inject:into:.
>> To execute a transformation and a reduction together, we can use
>> #transduce:reduce:init:.
>>
>> samples := Random new
>> transduce: scale * sides * count
>> reduce: collect
>> init: Bag new.
>>
>> We can also express the experiment as data-flow using #<~.
>> This enables us to build objects that can be re-used in other experiments.
>>
>> coin := sides <~ scale <~ Random new.
>> flip := Bag <~ count.
>>
>> Coin is an eduction, i.e., it binds transducers to a source and
>> understands #reduce:init: among others.
>> Flip is a transformed reduction, i.e., it binds transducers to a reducing
>> function and an initial value.
>> By sending #<~, we draw further samples from flipping the coin.
>>
>> samples := flip <~ coin.
>>
>> This yields a new Bag with another 1000 samples.
>>
>>
>>
>> # Basic Concepts
>>
>> ## Reducing Functions
>>
>> A reducing function represents a single step in processing a data
>> sequence.
>> It takes an accumulated result and a value, and returns a new accumulated
>> result.
>> For example:
>>
>> collect := [:col :e | col add: e; yourself].
>> sum := #+.
>>
>> A reducing function can also be ternary, i.e., it takes an accumulated
>> result, a key and a value.
>> For example:
>>
>> collect := [:dic :k :v | dict at: k put: v; yourself].
>>
>> Reducing functions may be equipped with an optional completing action.
>> After finishing processing, it is invoked exactly once, e.g., to free
>> resources.
>>
>> stream := [:str :e | str nextPut: each; yourself] completing: #close.
>> absSum := #+ completing: #abs
>>
>> A reducing function can end processing early by signaling Reduced with a
>> result.
>> This mechanism also enables the treatment of infinite sources.
>>
>> nonNil := [:res :e | e ifNil: [Reduced signalWith: res] ifFalse:
>> [res]].
>>
>> The primary approach to process a data sequence is the reducing protocol
>> with the messages #reduce:init: and #transduce:reduce:init: if transducers
>> are involved.
>> The behavior is similar to #inject:into: but in addition it takes care of:
>> - handling binary and ternary reducing functions,
>> - invoking the completing action after finishing, and
>> - stopping the reduction if Reduced is signaled.
>> The message #transduce:reduce:init: just combines the transformation and
>> the reducing step.
>>
>> However, as reducing functions are step-wise in nature, an application may
>> choose other means to process its data.
>>
>>
>> ## Reducibles
>>
>> A data source is called reducible if it implements the reducing protocol.
>> Default implementations are provided for collections and streams.
>> Additionally, blocks without an argument are reducible, too.
>> This allows to adapt to custom data sources without additional effort.
>> For example:
>>
>> "XStreams adaptor"
>> xstream := filename reading.
>> reducible := [[xstream get] on: Incomplete do: [Reduced signal]].
>>
>> "natural numbers"
>> n := 0.
>> reducible := [n := n+1].
>>
>>
>> ## Transducers
>>
>> A transducer is an object that transforms a reducing function into
>> another.
>> Transducers encapsulate common steps in processing data sequences, such as
>> map, filter, concatenate, and flatten.
>> A transducer transforms a reducing function into another via #transform:
>> in order to add those steps.
>> They can be composed using #* which yields a new transducer that does both
>> transformations.
>> Most transducers require an argument, typically blocks, symbols or
>> numbers:
>>
>> square := Map function: #squared.
>> take := Take number: 1000.
>>
>> To facilitate compact notation, the argument types implement corresponding
>> methods:
>>
>> squareAndTake := #squared map * 1000 take.
>>
>> Transducers requiring no argument are singletons and can be accessed by
>> their class name.
>>
>> flattenAndDedupe := Flatten * Dedupe.
>>
>>
>>
>> # Advanced Concepts
>>
>> ## Data flows
>>
>> Processing a sequence of data can often be regarded as a data flow.
>> The operator #<~ allows define a flow from a data source through
>> processing steps to a drain.
>> For example:
>>
>> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
>> fileOut writeStream <~ #isSeparator filter <~ fileIn readStream.
>>
>> In both examples #<~ is only used to set up the data flow using reducing
>> functions and transducers.
>> In contrast to streams, transducers are completely independent from input
>> and output sources.
>> Hence, we have a clear separation of reading data, writing data and
>> processing elements.
>> - Sources know how to iterate over data with a reducing function, e.g.,
>> via #reduce:init:.
>> - Drains know how to collect data using a reducing function.
>> - Transducers know how to process single elements.
>>
>>
>> ## Reductions
>>
>> A reduction binds an initial value or a block yielding an initial value to
>> a reducing function.
>> The idea is to define a ready-to-use process that can be applied in
>> different contexts.
>> Reducibles handle reductions via #reduce: and #transduce:reduce:
>> For example:
>>
>> sum := #+ init: 0.
>> sum1 := #(1 1 1) reduce: sum.
>> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
>>
>> asSet := [:set :e | set add: e; yourself] initializer: [Set new].
>> set1 := #(1 1 1) reduce: asSet.
>> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
>>
>> By combining a transducer with a reduction, a process can be further
>> modified.
>>
>> sumOdds := sum <~ #odd filter
>> setOdds := asSet <~ #odd filter
>>
>>
>> ## Eductions
>>
>> An eduction combines a reducible data sources with a transducer.
>> The idea is to define a transformed (virtual) data source that needs not
>> to be stored in memory.
>>
>> odds1 := #odd filter <~ #(1 2 3) readStream.
>> odds2 := #odd filter <~ (1 to 1000).
>>
>> Depending on the underlying source, eductions can be processed once
>> (streams, e.g., odds1) or multiple times (collections, e.g., odds2).
>> Since no intermediate data is stored, transducers actions are lazy, i.e.,
>> they are invoked each time the eduction is processed.
>>
>>
>>
>> # Origins
>>
>> Transducers is based on the same-named Clojure library and its ideas.
>> Please see:
>> http://clojure.org/transducers
>>
>>
>
June 2, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Stephane Ducasse
I have a design question
why the library is implemented in functional style vs messages?
I do not see why this is needed. To my eyes the compact notation
goes against readibility of code and it feels ad-hoc in Smalltalk.
I really prefer
square := Map function: #squared.
take := Take number: 1000.
Because I know that I can read it and understand it.
>From that perspective I prefer Xtreams.
Stef
On Wed, May 31, 2017 at 2:23 PM, Steffen Märcker <merkste(a)web.de> wrote:
> Hi,
>
> I am the developer of the library 'Transducers' for VisualWorks. It was
> formerly known as 'Reducers', but this name was a poor choice. I'd like to
> port it to Pharo, if there is any interest on your side. I hope to learn
> more about Pharo in this process, since I am mainly a VW guy. And most
> likely, I will come up with a bunch of questions. :-)
>
> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be very
> happy to hear your optinions, questions and I hope we can start a fruitful
> discussion - even if there is not Pharo port yet.
>
> Best, Steffen
>
>
>
> Transducers are building blocks that encapsulate how to process elements
> of a data sequence independently of the underlying input and output source.
>
>
>
> # Overview
>
> ## Encapsulate
> Implementations of enumeration methods, such as #collect:, have the logic
> how to process a single element in common.
> However, that logic is reimplemented each and every time. Transducers make
> it explicit and facilitate re-use and coherent behavior.
> For example:
> - #collect: requires mapping: (aBlock1 map)
> - #select: requires filtering: (aBlock2 filter)
>
>
> ## Compose
> In practice, algorithms often require multiple processing steps, e.g.,
> mapping only a filtered set of elements.
> Transducers are inherently composable, and hereby, allow to make the
> combination of steps explicit.
> Since transducers do not build intermediate collections, their composition
> is memory-efficient.
> For example:
> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map elements"
>
>
> ## Re-Use
> Transducers are decoupled from the input and output sources, and hence,
> they can be reused in different contexts.
> For example:
> - enumeration of collections
> - processing of streams
> - communicating via channels
>
>
>
> # Usage by Example
>
> We build a coin flipping experiment and count the occurrence of heads and
> tails.
>
> First, we associate random numbers with the sides of a coin.
>
> scale := [:x | (x * 2 + 1) floor] map.
> sides := #(heads tails) replace.
>
> Scale is a transducer that maps numbers x between 0 and 1 to 1 and 2.
> Sides is a transducer that replaces the numbers with heads an tails by
> lookup in an array.
> Next, we choose a number of samples.
>
> count := 1000 take.
>
> Count is a transducer that takes 1000 elements from a source.
> We keep track of the occurrences of heads an tails using a bag.
>
> collect := [:bag :c | bag add: c; yourself].
>
> Collect is binary block (reducing function) that collects events in a bag.
> We assemble the experiment by transforming the block using the transducers.
>
> experiment := (scale * sides * count) transform: collect.
>
> From left to right we see the steps involved: scale, sides, count and
> collect.
> Transforming assembles these steps into a binary block (reducing function)
> we can use to run the experiment.
>
> samples := Random new
> reduce: experiment
> init: Bag new.
>
> Here, we use #reduce:init:, which is mostly similar to #inject:into:.
> To execute a transformation and a reduction together, we can use
> #transduce:reduce:init:.
>
> samples := Random new
> transduce: scale * sides * count
> reduce: collect
> init: Bag new.
>
> We can also express the experiment as data-flow using #<~.
> This enables us to build objects that can be re-used in other experiments.
>
> coin := sides <~ scale <~ Random new.
> flip := Bag <~ count.
>
> Coin is an eduction, i.e., it binds transducers to a source and
> understands #reduce:init: among others.
> Flip is a transformed reduction, i.e., it binds transducers to a reducing
> function and an initial value.
> By sending #<~, we draw further samples from flipping the coin.
>
> samples := flip <~ coin.
>
> This yields a new Bag with another 1000 samples.
>
>
>
> # Basic Concepts
>
> ## Reducing Functions
>
> A reducing function represents a single step in processing a data sequence.
> It takes an accumulated result and a value, and returns a new accumulated
> result.
> For example:
>
> collect := [:col :e | col add: e; yourself].
> sum := #+.
>
> A reducing function can also be ternary, i.e., it takes an accumulated
> result, a key and a value.
> For example:
>
> collect := [:dic :k :v | dict at: k put: v; yourself].
>
> Reducing functions may be equipped with an optional completing action.
> After finishing processing, it is invoked exactly once, e.g., to free
> resources.
>
> stream := [:str :e | str nextPut: each; yourself] completing: #close.
> absSum := #+ completing: #abs
>
> A reducing function can end processing early by signaling Reduced with a
> result.
> This mechanism also enables the treatment of infinite sources.
>
> nonNil := [:res :e | e ifNil: [Reduced signalWith: res] ifFalse:
> [res]].
>
> The primary approach to process a data sequence is the reducing protocol
> with the messages #reduce:init: and #transduce:reduce:init: if transducers
> are involved.
> The behavior is similar to #inject:into: but in addition it takes care of:
> - handling binary and ternary reducing functions,
> - invoking the completing action after finishing, and
> - stopping the reduction if Reduced is signaled.
> The message #transduce:reduce:init: just combines the transformation and
> the reducing step.
>
> However, as reducing functions are step-wise in nature, an application may
> choose other means to process its data.
>
>
> ## Reducibles
>
> A data source is called reducible if it implements the reducing protocol.
> Default implementations are provided for collections and streams.
> Additionally, blocks without an argument are reducible, too.
> This allows to adapt to custom data sources without additional effort.
> For example:
>
> "XStreams adaptor"
> xstream := filename reading.
> reducible := [[xstream get] on: Incomplete do: [Reduced signal]].
>
> "natural numbers"
> n := 0.
> reducible := [n := n+1].
>
>
> ## Transducers
>
> A transducer is an object that transforms a reducing function into another.
> Transducers encapsulate common steps in processing data sequences, such as
> map, filter, concatenate, and flatten.
> A transducer transforms a reducing function into another via #transform:
> in order to add those steps.
> They can be composed using #* which yields a new transducer that does both
> transformations.
> Most transducers require an argument, typically blocks, symbols or numbers:
>
> square := Map function: #squared.
> take := Take number: 1000.
>
> To facilitate compact notation, the argument types implement corresponding
> methods:
>
> squareAndTake := #squared map * 1000 take.
>
> Transducers requiring no argument are singletons and can be accessed by
> their class name.
>
> flattenAndDedupe := Flatten * Dedupe.
>
>
>
> # Advanced Concepts
>
> ## Data flows
>
> Processing a sequence of data can often be regarded as a data flow.
> The operator #<~ allows define a flow from a data source through
> processing steps to a drain.
> For example:
>
> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
> fileOut writeStream <~ #isSeparator filter <~ fileIn readStream.
>
> In both examples #<~ is only used to set up the data flow using reducing
> functions and transducers.
> In contrast to streams, transducers are completely independent from input
> and output sources.
> Hence, we have a clear separation of reading data, writing data and
> processing elements.
> - Sources know how to iterate over data with a reducing function, e.g.,
> via #reduce:init:.
> - Drains know how to collect data using a reducing function.
> - Transducers know how to process single elements.
>
>
> ## Reductions
>
> A reduction binds an initial value or a block yielding an initial value to
> a reducing function.
> The idea is to define a ready-to-use process that can be applied in
> different contexts.
> Reducibles handle reductions via #reduce: and #transduce:reduce:
> For example:
>
> sum := #+ init: 0.
> sum1 := #(1 1 1) reduce: sum.
> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
>
> asSet := [:set :e | set add: e; yourself] initializer: [Set new].
> set1 := #(1 1 1) reduce: asSet.
> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
>
> By combining a transducer with a reduction, a process can be further
> modified.
>
> sumOdds := sum <~ #odd filter
> setOdds := asSet <~ #odd filter
>
>
> ## Eductions
>
> An eduction combines a reducible data sources with a transducer.
> The idea is to define a transformed (virtual) data source that needs not
> to be stored in memory.
>
> odds1 := #odd filter <~ #(1 2 3) readStream.
> odds2 := #odd filter <~ (1 to 1000).
>
> Depending on the underlying source, eductions can be processed once
> (streams, e.g., odds1) or multiple times (collections, e.g., odds2).
> Since no intermediate data is stored, transducers actions are lazy, i.e.,
> they are invoked each time the eduction is processed.
>
>
>
> # Origins
>
> Transducers is based on the same-named Clojure library and its ideas.
> Please see:
> http://clojure.org/transducers
>
>
June 2, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Stephane Ducasse
Hi steffen
This is a great news. We need cool frameworks.
- There is a package on cincom store to support the migration from VW to
Pharo. FileOuter something. The name escapes my mind now. We updated it
last year to help porting one application to Pharo.
- I can help producing a nice document :)
On Wed, May 31, 2017 at 2:23 PM, Steffen Märcker <merkste(a)web.de> wrote:
> Hi,
>
> I am the developer of the library 'Transducers' for VisualWorks. It was
> formerly known as 'Reducers', but this name was a poor choice. I'd like to
> port it to Pharo, if there is any interest on your side. I hope to learn
> more about Pharo in this process, since I am mainly a VW guy. And most
> likely, I will come up with a bunch of questions. :-)
>
> Meanwhile, I'll cross-post the introduction from VWnc below. I'd be very
> happy to hear your optinions, questions and I hope we can start a fruitful
> discussion - even if there is not Pharo port yet.
>
> Best, Steffen
>
>
>
> Transducers are building blocks that encapsulate how to process elements
> of a data sequence independently of the underlying input and output source.
>
>
>
> # Overview
>
> ## Encapsulate
> Implementations of enumeration methods, such as #collect:, have the logic
> how to process a single element in common.
> However, that logic is reimplemented each and every time. Transducers make
> it explicit and facilitate re-use and coherent behavior.
> For example:
> - #collect: requires mapping: (aBlock1 map)
> - #select: requires filtering: (aBlock2 filter)
>
>
> ## Compose
> In practice, algorithms often require multiple processing steps, e.g.,
> mapping only a filtered set of elements.
> Transducers are inherently composable, and hereby, allow to make the
> combination of steps explicit.
> Since transducers do not build intermediate collections, their composition
> is memory-efficient.
> For example:
> - (aBlock1 filter) * (aBlock2 map) "(1.) filter and (2.) map elements"
>
>
> ## Re-Use
> Transducers are decoupled from the input and output sources, and hence,
> they can be reused in different contexts.
> For example:
> - enumeration of collections
> - processing of streams
> - communicating via channels
>
>
>
> # Usage by Example
>
> We build a coin flipping experiment and count the occurrence of heads and
> tails.
>
> First, we associate random numbers with the sides of a coin.
>
> scale := [:x | (x * 2 + 1) floor] map.
> sides := #(heads tails) replace.
>
> Scale is a transducer that maps numbers x between 0 and 1 to 1 and 2.
> Sides is a transducer that replaces the numbers with heads an tails by
> lookup in an array.
> Next, we choose a number of samples.
>
> count := 1000 take.
>
> Count is a transducer that takes 1000 elements from a source.
> We keep track of the occurrences of heads an tails using a bag.
>
> collect := [:bag :c | bag add: c; yourself].
>
> Collect is binary block (reducing function) that collects events in a bag.
> We assemble the experiment by transforming the block using the transducers.
>
> experiment := (scale * sides * count) transform: collect.
>
> From left to right we see the steps involved: scale, sides, count and
> collect.
> Transforming assembles these steps into a binary block (reducing function)
> we can use to run the experiment.
>
> samples := Random new
> reduce: experiment
> init: Bag new.
>
> Here, we use #reduce:init:, which is mostly similar to #inject:into:.
> To execute a transformation and a reduction together, we can use
> #transduce:reduce:init:.
>
> samples := Random new
> transduce: scale * sides * count
> reduce: collect
> init: Bag new.
>
> We can also express the experiment as data-flow using #<~.
> This enables us to build objects that can be re-used in other experiments.
>
> coin := sides <~ scale <~ Random new.
> flip := Bag <~ count.
>
> Coin is an eduction, i.e., it binds transducers to a source and
> understands #reduce:init: among others.
> Flip is a transformed reduction, i.e., it binds transducers to a reducing
> function and an initial value.
> By sending #<~, we draw further samples from flipping the coin.
>
> samples := flip <~ coin.
>
> This yields a new Bag with another 1000 samples.
>
>
>
> # Basic Concepts
>
> ## Reducing Functions
>
> A reducing function represents a single step in processing a data sequence.
> It takes an accumulated result and a value, and returns a new accumulated
> result.
> For example:
>
> collect := [:col :e | col add: e; yourself].
> sum := #+.
>
> A reducing function can also be ternary, i.e., it takes an accumulated
> result, a key and a value.
> For example:
>
> collect := [:dic :k :v | dict at: k put: v; yourself].
>
> Reducing functions may be equipped with an optional completing action.
> After finishing processing, it is invoked exactly once, e.g., to free
> resources.
>
> stream := [:str :e | str nextPut: each; yourself] completing: #close.
> absSum := #+ completing: #abs
>
> A reducing function can end processing early by signaling Reduced with a
> result.
> This mechanism also enables the treatment of infinite sources.
>
> nonNil := [:res :e | e ifNil: [Reduced signalWith: res] ifFalse:
> [res]].
>
> The primary approach to process a data sequence is the reducing protocol
> with the messages #reduce:init: and #transduce:reduce:init: if transducers
> are involved.
> The behavior is similar to #inject:into: but in addition it takes care of:
> - handling binary and ternary reducing functions,
> - invoking the completing action after finishing, and
> - stopping the reduction if Reduced is signaled.
> The message #transduce:reduce:init: just combines the transformation and
> the reducing step.
>
> However, as reducing functions are step-wise in nature, an application may
> choose other means to process its data.
>
>
> ## Reducibles
>
> A data source is called reducible if it implements the reducing protocol.
> Default implementations are provided for collections and streams.
> Additionally, blocks without an argument are reducible, too.
> This allows to adapt to custom data sources without additional effort.
> For example:
>
> "XStreams adaptor"
> xstream := filename reading.
> reducible := [[xstream get] on: Incomplete do: [Reduced signal]].
>
> "natural numbers"
> n := 0.
> reducible := [n := n+1].
>
>
> ## Transducers
>
> A transducer is an object that transforms a reducing function into another.
> Transducers encapsulate common steps in processing data sequences, such as
> map, filter, concatenate, and flatten.
> A transducer transforms a reducing function into another via #transform:
> in order to add those steps.
> They can be composed using #* which yields a new transducer that does both
> transformations.
> Most transducers require an argument, typically blocks, symbols or numbers:
>
> square := Map function: #squared.
> take := Take number: 1000.
>
> To facilitate compact notation, the argument types implement corresponding
> methods:
>
> squareAndTake := #squared map * 1000 take.
>
> Transducers requiring no argument are singletons and can be accessed by
> their class name.
>
> flattenAndDedupe := Flatten * Dedupe.
>
>
>
> # Advanced Concepts
>
> ## Data flows
>
> Processing a sequence of data can often be regarded as a data flow.
> The operator #<~ allows define a flow from a data source through
> processing steps to a drain.
> For example:
>
> squares := Set <~ 1000 take <~ #squared map <~ (1 to: 1000).
> fileOut writeStream <~ #isSeparator filter <~ fileIn readStream.
>
> In both examples #<~ is only used to set up the data flow using reducing
> functions and transducers.
> In contrast to streams, transducers are completely independent from input
> and output sources.
> Hence, we have a clear separation of reading data, writing data and
> processing elements.
> - Sources know how to iterate over data with a reducing function, e.g.,
> via #reduce:init:.
> - Drains know how to collect data using a reducing function.
> - Transducers know how to process single elements.
>
>
> ## Reductions
>
> A reduction binds an initial value or a block yielding an initial value to
> a reducing function.
> The idea is to define a ready-to-use process that can be applied in
> different contexts.
> Reducibles handle reductions via #reduce: and #transduce:reduce:
> For example:
>
> sum := #+ init: 0.
> sum1 := #(1 1 1) reduce: sum.
> sum2 := (1 to: 1000) transduce: #odd filter reduce: sum.
>
> asSet := [:set :e | set add: e; yourself] initializer: [Set new].
> set1 := #(1 1 1) reduce: asSet.
> set2 := #(1 to: 1000) transduce: #odd filter reduce: asSet.
>
> By combining a transducer with a reduction, a process can be further
> modified.
>
> sumOdds := sum <~ #odd filter
> setOdds := asSet <~ #odd filter
>
>
> ## Eductions
>
> An eduction combines a reducible data sources with a transducer.
> The idea is to define a transformed (virtual) data source that needs not
> to be stored in memory.
>
> odds1 := #odd filter <~ #(1 2 3) readStream.
> odds2 := #odd filter <~ (1 to 1000).
>
> Depending on the underlying source, eductions can be processed once
> (streams, e.g., odds1) or multiple times (collections, e.g., odds2).
> Since no intermediate data is stored, transducers actions are lazy, i.e.,
> they are invoked each time the eduction is processed.
>
>
>
> # Origins
>
> Transducers is based on the same-named Clojure library and its ideas.
> Please see:
> http://clojure.org/transducers
>
>
June 2, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Yanni Chiu
To get the extension methods into the Transducers package, the following
worked for me - edit the category to have the prefix '*Transducers-'
2710c2710
< !Number methodsFor: 'transforming' stamp: ' 2/6/17 15:38'!
---
> !Number methodsFor: '*Transducers-transforming' stamp: ' 2/6/17 15:38'!
On Fri, Jun 2, 2017 at 11:05 AM, Steffen Märcker <merkste(a)web.de> wrote:
> Dear all,
>
> thanks for the many suggestions. I didn't had time to test all
> import/export ways yet. But for now, I can report on two:
>
> 1) NGFileOuter
> Unfortunately It raised several MNUs in my image. I'll investigate them
> later.
>
> 2) FileOut30 (VW Contributed)
> I was able to file out the code except for the package definition.
> Replacing {category: ''} in the class definitions with {package:
> 'Transducers'} fixed that. However, methods that extend existing classes
> did not end up in the Transducers package. Is there a similar easy change
> to the file-out making that happen? Also I'd like to add the package
> comment if that's possible.
>
> Most things appear to work as far as I can see. Two exceptions:
> 1) Random is a subclass of Stream in VW and in Pharo it is not. Hence,
> I'll have to copy some methods from Stream to Random.
> 2) I used #beImmutable in VW but I couldn't yet figure out how to make
> objects immutable in Pharo.
>
> However, until the tests are ported, I cannot guarantee. Porting the test
> suite will be another beast, since I rely on the excellent mocking/stubbing
> library DoubleAgents by Randy Coulman. I am not sure how I will handle
> that. In general, I think it would be really worth the effort to be ported
> to Pharo, too. DoubleAgents is pretty powerful and produces easy to read
> and understand mocking/stubbing code. Personally, I prefer it clearly,
> e.g., over Mocketry (no offence intended!).
>
> Attached you'll find the file-out that I loaded into Pharo. The issues
> above are not addressed yet. However, the following example works:
>
> | scale sides count collect experiment random samples coin flip |
> scale := [:x | (x * 2 + 1) floor] map.
> sides := #(heads tails) replace.
> count := 1000 take.
> collect := [:bag :c | bag add: c; yourself].
> experiment := (scale * sides * count) transform: collect.
> random := #(0.1 0.3 0.4 0.5 0.6 0.7 0.8 0.9).
>
> samples := random
> reduce: experiment
> init: Bag new.
>
> samples := random
> transduce: scale * sides * count
> reduce: collect
> init: Bag new.
>
> coin := sides <~ scale <~ random.
> flip := Bag <~ count.
>
> samples := flip <~ coin.
>
>
> Best, Steffen
>
>
>
> Am .06.2017, 08:16 Uhr, schrieb Stephane Ducasse <stepharo.self(a)gmail.com
> >:
>
> There is a package for that NGFileOuter or something like that on cincom
>> store.
>> We used it for mobydic code.
>>
>> On Wed, May 31, 2017 at 6:35 PM, Alexandre Bergel <
>> alexandre.bergel(a)me.com>
>> wrote:
>>
>> If I remember correctly, there is a parcel in VisualWorks to export a file
>>> out (Squeak format).
>>>
>>> @Milton, can you give a hand to Steffen?
>>>
>>> Alexandre
>>> --
>>> _,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
>>> Alexandre Bergel http://www.bergel.eu
>>> ^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
>>>
>>>
>>>
>>> On May 31, 2017, at 10:32 AM, Steffen Märcker <merkste(a)web.de> wrote:
>>>
>>> Thanks for the encouraging response! First question: Which is the
>>> recommended (friction free) way to exchange code between VW and Pharo?
>>>
>>> Cheers!
>>> Steffen
>>>
>>> Am .05.2017, 16:22 Uhr, schrieb Alexandre Bergel <
>>> alexandre.bergel(a)me.com
>>> >:
>>>
>>> I second Sven. This is very exciting!
>>>
>>> Let us know when you have something ready to be tested.
>>>
>>> Alexandre
>>>
>>>
>>>
>>>
>>>
June 2, 2017
Re: [Pharo-users] Can we auto translate Python to Smalltalk?
by Julien Delplanque
Hello,
Actually I did the opposite to be able to use Python 3 libraries from Pharo.
It is not complete, but you may want to take a look at it [1]. Using
this lib
you can craft a Python 3 AST and generate its source code.
I guess there is a way to access the AST of a Python program using the API.
Now, you have to see if it is always possible to convert a Python AST to
a Pharo AST.
One day, I read about someone that converted Python to Ruby (or the
opposite) using
bytecode translation. Maybe it is another way to do it.
Julien
Links:
[1]: https://github.com/juliendelplanque/Python3Generator
On 02/06/17 17:20, askoh wrote:
> Python and JavaScript are driving the movement to Dynamic Languages. In
> particular, Python is the language of choice to teach students programming
> in universities. So, Smalltalk stands to gain from this shift. We all know
> that Smalltalk has the best environment. But we lack the diverse code base.
> Can we patch that gap with automatic translation from Python to Smalltalk?
> How feasible would it be to auto translate SciPy to SciSmalltalk? Even if it
> is imperfect, can we cut the effort by 50% or 80%?
>
> All the best,
> Aik-Siong Koh
>
>
>
> --
> View this message in context: http://forum.world.st/Can-we-auto-translate-Python-to-Smalltalk-tp4949015.h…
> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
>
June 2, 2017
Can we auto translate Python to Smalltalk?
by askoh
Python and JavaScript are driving the movement to Dynamic Languages. In
particular, Python is the language of choice to teach students programming
in universities. So, Smalltalk stands to gain from this shift. We all know
that Smalltalk has the best environment. But we lack the diverse code base.
Can we patch that gap with automatic translation from Python to Smalltalk?
How feasible would it be to auto translate SciPy to SciSmalltalk? Even if it
is imperfect, can we cut the effort by 50% or 80%?
All the best,
Aik-Siong Koh
--
View this message in context: http://forum.world.st/Can-we-auto-translate-Python-to-Smalltalk-tp4949015.h…
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
June 2, 2017
Re: [Pharo-users] Porting Transducers to Pharo
by Steffen Märcker
Dear all,
thanks for the many suggestions. I didn't had time to test all
import/export ways yet. But for now, I can report on two:
1) NGFileOuter
Unfortunately It raised several MNUs in my image. I'll investigate them
later.
2) FileOut30 (VW Contributed)
I was able to file out the code except for the package definition.
Replacing {category: ''} in the class definitions with {package:
'Transducers'} fixed that. However, methods that extend existing classes
did not end up in the Transducers package. Is there a similar easy change
to the file-out making that happen? Also I'd like to add the package
comment if that's possible.
Most things appear to work as far as I can see. Two exceptions:
1) Random is a subclass of Stream in VW and in Pharo it is not. Hence,
I'll have to copy some methods from Stream to Random.
2) I used #beImmutable in VW but I couldn't yet figure out how to make
objects immutable in Pharo.
However, until the tests are ported, I cannot guarantee. Porting the test
suite will be another beast, since I rely on the excellent
mocking/stubbing library DoubleAgents by Randy Coulman. I am not sure how
I will handle that. In general, I think it would be really worth the
effort to be ported to Pharo, too. DoubleAgents is pretty powerful and
produces easy to read and understand mocking/stubbing code. Personally, I
prefer it clearly, e.g., over Mocketry (no offence intended!).
Attached you'll find the file-out that I loaded into Pharo. The issues
above are not addressed yet. However, the following example works:
| scale sides count collect experiment random samples coin flip |
scale := [:x | (x * 2 + 1) floor] map.
sides := #(heads tails) replace.
count := 1000 take.
collect := [:bag :c | bag add: c; yourself].
experiment := (scale * sides * count) transform: collect.
random := #(0.1 0.3 0.4 0.5 0.6 0.7 0.8 0.9).
samples := random
reduce: experiment
init: Bag new.
samples := random
transduce: scale * sides * count
reduce: collect
init: Bag new.
coin := sides <~ scale <~ random.
flip := Bag <~ count.
samples := flip <~ coin.
Best, Steffen
Am .06.2017, 08:16 Uhr, schrieb Stephane Ducasse <stepharo.self(a)gmail.com>:
> There is a package for that NGFileOuter or something like that on cincom
> store.
> We used it for mobydic code.
>
> On Wed, May 31, 2017 at 6:35 PM, Alexandre Bergel
> <alexandre.bergel(a)me.com>
> wrote:
>
>> If I remember correctly, there is a parcel in VisualWorks to export a
>> file
>> out (Squeak format).
>>
>> @Milton, can you give a hand to Steffen?
>>
>> Alexandre
>> --
>> _,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
>> Alexandre Bergel http://www.bergel.eu
>> ^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
>>
>>
>>
>> On May 31, 2017, at 10:32 AM, Steffen Märcker <merkste(a)web.de> wrote:
>>
>> Thanks for the encouraging response! First question: Which is the
>> recommended (friction free) way to exchange code between VW and Pharo?
>>
>> Cheers!
>> Steffen
>>
>> Am .05.2017, 16:22 Uhr, schrieb Alexandre Bergel
>> <alexandre.bergel(a)me.com
>> >:
>>
>> I second Sven. This is very exciting!
>>
>> Let us know when you have something ready to be tested.
>>
>> Alexandre
>>
>>
>>
>>
>>
June 2, 2017