"Doc O'Leary" <droleary / subsume.com> wrote in message
news:251120011105195454%droleary / subsume.com...
> In article <Su_L7.44988$RG1.23138548 / news1.rdc1.sfba.home.com>, David
> Simmons <david.simmons / smallscript.com> wrote:
>
>
    [...snip...]

I already responded the original problem presented in Waldemar Horwat's
JavaScript 2.0 slides. Let me demonstrate a different use of selector
namespaces which cannot be solved through versioning.

In this example I will also mention the use of indirect use of concrete
interfaces for providing implementation behavior.
----

Problem: Two unrelated Smalltalk developers are creating modules for
handling monetary units [grossly simplified].

As each independently thinks about their design, one of the problems they
encounter is that of converting string representations into money objects.
They both decide that it would be most appropriate (from a design usage
point of view) to enable <String> objects to handle conversions to monetary
unit objects.

I.e., they would like to enable expressions like:

    '$50.00' asMoney.  "possibly #asDollars"

For whatever reasons, they have both decided that some class (which they did
not write/own -- in this case <String>), is the most appropriate place to
implement a method (which they will write and which will owned by their
projects/modules).

So, naively they write:

----------------------------
Party One's Monetary Package
----------------------------
<Project name: USCurrency>
Class name: Dollars
{
    ...
    Method [
    + <Dollars> aValue
        ...
    ]
}
Method class: String [
asMoney
    ...
]
</Project>

----------------------------
Party Two's Monetary Package
----------------------------
<Project name: CanadianCurrency>
Class name: Dollars
{
    ...
    Method [
    + <Dollars> aValue
        ...
    ]
}
Method class: String [
asMoney
    ...
]
</Project>

====
All is well, they've versioned, built-unit tests, etc. They even develop
sophisticated tools and release them to 3rd parties for consumption. Any
string can be sent the message #asMoney and it does the "right" thing in the
unit tests, etc.

A third party integrator comes along and has the requirement of writing a
program that requires both US and Canadian currency operations. They are
given the requirement that they must use the party-one's and party-two's
packages (rather than writing their own). They may even be in the
uncomfortable but likely position that they do not have source to the
packages [as would commonly be the case for static languages and platforms
based on binary component approaches like .NET].

Now we have a serious problem. Both parties have made implementations that
appear to conflict. First, without namespaces the class name <Dollars> will
collide. Even with namespaces, the #asMoney methods on <String>, will
conflict. Since the #asMoney methods (minimally) yield unrelated return
types. I.e., one party returns a unit of Candian <Dollars> and the other
party returns a unit of US <Dollars>.
---

Arguably, at this point, one would say namespaces would solve the <Dollars>
problem. And there is no way they should be modifying the <String> class
they don't own. Heck let's add language features to seal and finalize things
so they can't do this even in dynamic languages that enable runtime schema
changes.

But is that really the right answer? After all, if the they had
owned/created the <String> class we would say there was no problem with
adding a monetary conversion method to it [although some people might think,
hey, String is a special class and should not be touched -- but, think
again, why is it special?]. In general, as an object-oriented approach we
encourage this type of design decision as a well placed responsibility.

So why is it wrong here? Is it because it is inherently wrong, or is it
because implementation constraints and existing language semantics of
static-languages (and to some degree dynamic languages) have creeped in to
provide rules we should question?

But, if we could offer a uniform technique that allowed one to "encapsulate"
changes to our own code base and yet share our implementation with others,
then it would be fine. This is a feature that has been understood in various
non-oo imperative/function language module systems. So why not allow it in
class-based dynamic language OO systems...

Again, selector-namespaces allow us to do just that. If we could "scope" the
#asMoney methods provided by party-one and party-two then we could provide
this capability. [add concrete Interfaces to this and we have an even better
general solution].

====
Revising the code we write it as:

----------------------------
Party One's Monetary Package
----------------------------
<Project name: USCurrency>
Class name: Dollars
{
    ...
    Method [
    + <Dollars> aValue
        ...
    ]
}
Method class: String scope: USCurrency [
asMoney
    ...
]
</Project>

----------------------------
Party Two's Monetary Package
----------------------------
<Project name: CanadianCurrency>
Class name: Dollars
{
    ...
    Method [
    + <Dollars> aValue
        ...
    ]
}
Method class: String scope: CandianCurrency [
asMoney
    ...
]
</Project>

====
We also note that in a typical Smalltalk IDE, this scoping would be provided
by default by the tools for any methods we wrote onto classes which were not
contained within the project.

Now our 3rd party, who needed to implement a single application that used
both libraries can do so without conflicts.

The <Dollars> classes are distinguished through namespaces (remembering that
modules are classes and classes are namespaces). Both classes
<USCurrency.Dollars> and <CanadianCurrency.Dollars> comfortably exist.

The #asMoney methods both reside in <String> and have their method
characteristics set to:
Party one's USCurrency version of <String> #asMoney has: the selector
#USCurrency.asMoney; and the module attribute set to <USCurrency> to enable
versioned unloading/reloading of the module.

Party two's CanadianCurrency version of <String> #asMoney has: the selector
#CanadianCurrency.asMoney; and the module attribute set to
<CanadianCurrency> to enable versioned unloading/reloading of the module.

All the code in party one's tools will have specified access to <USCurrency>
as a namespace, and will not have access to party two's <CanadianCurrency>
namespace (because they did not know about it). Thus any of party one's
code will always bind to the #USCurrency.asMoney method in <String>.

The same can now be said for party two's code. All the code in party two's
tools will have specified access to <CanadianCurrency> as a namespace, and
will not have access to party one's <USCurrency> namespace (because they did
not know about it). Thus any of party one's  code will always bind to the
#CanadianCurrency.asMoney method in <String>.
----
If our 3rd party wants to write code that references both libraries they
will need to specify the particular namespaces they are referring to. Let's
assume they decide to write code to convert both Canadian and US dollars. So
they would like to have methods called #asCanadianDollars and #asUSDollars,
but they want to be insulated from implementation changes provided by party
one and/or party two's version updates.

They might write: (noting that a typical Smalltalk IDE would provide the
scoping attribute by default for methods on external classes)

<Project name: 3rdParty>
Requires module: USCurrency.       "versioning prequisites elided"
Requires module: CanadianCurrency. "versioning prequisites elided"

Method class: String scope: 3rdParty [
asCanadianDollars
    ^self #CanadianCurrency.asMoney
]
Method class: String scope: 3rdParty [
asUSDollars
    ^self #USCurrency.asMoney
]

.... other project code and classes here...

</Project>

===================

The interfaces technique would be written slightly differently (and I am not
really giving it due consideration in picking names for this grossly
simplified example, but OTOH I am will not subsequently be particularly
constrained by my up-front decisions either).

Here it is, but since I am running out of time I won't particularly explain
it now. I'll leave that to the reader and perhaps subsequent posts.

----------------------------
Party One's Monetary Package
----------------------------
<Project name: USCurrency>
Class name: Dollars
{
    ...
    Method [
    + <Dollars> aValue
        ...
    ]
}

Interface name: IMonetaryConversion
    default-scope: USCurrency
{
    Method [
    asMoney
        ...
    ]
    ... other methods here...
}

Function [
Initialize
    String addInterface: IMonetaryConversion.
]

Function [
Finalize
    String removeInterface: IMonetaryConversion.
]
</Project>

-- Dave S. [www.smallscript.org]