233 views

Skip to first unread message

Nov 3, 2009, 2:58:33 AM11/3/09

to

I was experimenting with vaguely OOP-like wrappers around data similar

to how Twitter.m does things:

to how Twitter.m does things:

http://blog.wolfram.com/2009/04/30/twittering-with-mathematica/

I was experimenting with "mutable objects" and I'm running into a

scoping problem of some type that I don't understand. Here's some

sample code creating a wrapper around an "account balance":

In[1]:= {NAME, BALANCE} = Range[2]

Out[1]= {1, 2}

In[2]:= create[name_, balance_] := Account[name, balance]

In[3]:= getName[account_Account] := account[[NAME]]

In[4]:= getBalance[account_Account] := account[[BALANCE]]

In[5]:= deposit[account_Account, amount_] :=

account[[BALANCE]] += amount

The deposit function doesn't work, though:

In[6]:= a = create["test", 100]

Out[6]= Account["test", 100]

In[7]:= getBalance[a]

Out[7]= 100

In[8]:= deposit[a, 25]

During evaluation of In[8]:= Set::setps: Account[test,100] in the part

assignment is not a symbol. >>

Out[8]= 125

In[9]:= getBalance[a]

Out[9]= 100

But here's what I'm confused; if I do what getBalance does manually, it

works fine:

In[10]:= a[[BALANCE]] += 25

Out[10]= 125

In[11]:= a

Out[11]= Account["test", 125]

The Set::setps error is about Blocks so I suppose I'm running into some

scoping issue but I don't follow what it is. What am I missing here?

What's the right way to write getBalance?

Do Mathematica users find Twitter.m's approach to wrapping around

objects palatable in the first place? (My eventual application is for a

wrapper around tensor objects where multiple things have to be carted

around and the normal display of such objects would be far too ungainly

to be acceptable anyway.)

Thanks.

--

Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/

San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis

Wyrd has swept all my kin / all the brave chiefs away! / Now I must

follow them! -- Beowulf

Nov 4, 2009, 1:32:19 AM11/4/09

to

You might try with this "overloading" approach:

{NAME, BALANCE} = Range[2];

ClearAll[Account, create, getName, getBalance, deposit];

Account /: (f_[p___, Account[t_, n_], m___] /;

MemberQ[{Plus, Subtract, Times, Divide, Power}, f]) :=

Account[t, f[p, n, m]];

create[name_, balance_] := Account[name, balance];

getName[account_Account] := account[[NAME]];

getBalance[account_Account] := account[[BALANCE]];

deposit[account_Account, amount_] := account = account + amount;

This is the resulting behavior:

In[8]:= a=create["test",Random[Integer,{0,200}]]

Out[8]= Account(test,176)

In[9]:= getBalance[a]

Out[9]= 176

In[10]:= b=a+10

Out[10]= Account(test,186)

In[11]:= b=a 10

Out[11]= Account(test,1760)

In[12]:= b=10a

Out[12]= Account(test,1760)

In[13]:= b=a/10

Out[13]= Account(test,88/5)

In[14]:= b=10/a

Out[14]= Account(test,5/88)

In[15]:= b=a^2

Out[15]= Account(test,30976)

In[16]:= deposit[a,25]

Out[16]= Account(test,201)

In[17]:= deposit[b,25]

Out[17]= Account(test,31001)

In[18]:= a

Out[18]= Account(test,201)

In[19]:= b

Out[19]= Account(test,31001)

ADL

On Nov 3, 8:58 am, Erik Max Francis <m...@alcyone.com> wrote:

> I was experimenting with vaguely OOP-like wrappers around data similar

> to how Twitter.m does things:

>

> http://blog.wolfram.com/2009/04/30/twittering-with-mathema=

> objects palatable in the first place? (My eventual application is for =

a

> wrapper around tensor objects where multiple things have to be carted

> around and the normal display of such objects would be far too ungainly

> to be acceptable anyway.)

>

> Thanks.

>

> --

> Erik Max Francis && m...@alcyone.com &&http://www.alcyone.com/max/

> San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis

> Wyrd has swept all my kin / all the brave chiefs away! / Now I mus=

t

> follow them! -- Beowulf

Nov 4, 2009, 1:36:17 AM11/4/09

to

Hi Erik,

what you want to do is a bit tricky.

By: deposit[a, 25] you want to assigne to the variable "a" an expression

like: Account[..,..]

By default all arguments to a function are evaluated prior to calling

the function. Therefore your variable "account" does not contain "a" but

the expression "Account["test", 100]". To obtain the variable name you

must prevent the evaluation by e.g. specifying;

SetAttributes[deposit,HoldFirst].

Inside the function you must again take precautiion against evaluation

of the variable by specifying e.g.:

Unevaluated[account] =

As you have not defined an addition rule for "Account" we need to create

the full expression on the right side of the assignment:

Unevaluated[account] = Account[account[[1]], account[[2]] + amount]

Here "account" contains the evaluated "a", namely: "Account["test", 100]"

Therefore, deposit would be declared e.g. like:

SetAttributes[deposit, HoldFirst];

deposit[account_, amount_] :=

Unevaluated[account] = Account[account[[1]], account[[2]] + amount]

Daniel

Nov 4, 2009, 1:39:40 AM11/4/09

to

On Nov 3, 2:58 am, Erik Max Francis <m...@alcyone.com> wrote:

> The deposit function doesn't work, though:

>

> In[6]:= a = create["test", 100]

>

> Out[6]= Account["test", 100]

>

> In[7]:= getBalance[a]

>

> Out[7]= 100

>

> In[8]:= deposit[a, 25]

>

> During evaluation of In[8]:= Set::setps: Account[test,100] in the part

> assignment is not a symbol. >>

>

> Out[8]= 125

>

> In[9]:= getBalance[a]

>

> Out[9]= 100

>

> But here's what I'm confused; if I do what getBalance does manually, it

> works fine:

>

> In[10]:= a[[BALANCE]] += 25

>

> Out[10]= 125

>

> In[11]:= a

>

> Out[11]= Account["test", 125]

>

> The Set::setps error is about Blocks so I suppose I'm running into some

> scoping issue but I don't follow what it is. What am I missing here?

> What's the right way to write getBalance?

> The deposit function doesn't work, though:

>

> In[6]:= a = create["test", 100]

>

> Out[6]= Account["test", 100]

>

> In[7]:= getBalance[a]

>

> Out[7]= 100

>

> In[8]:= deposit[a, 25]

>

> During evaluation of In[8]:= Set::setps: Account[test,100] in the part

> assignment is not a symbol. >>

>

> Out[8]= 125

>

> In[9]:= getBalance[a]

>

> Out[9]= 100

>

> But here's what I'm confused; if I do what getBalance does manually, it

> works fine:

>

> In[10]:= a[[BALANCE]] += 25

>

> Out[10]= 125

>

> In[11]:= a

>

> Out[11]= Account["test", 125]

>

> The Set::setps error is about Blocks so I suppose I'm running into some

> scoping issue but I don't follow what it is. What am I missing here?

> What's the right way to write getBalance?

By the time deposit[] is called "a" has already evaluated to Account

["test", 100], which means a[[BALANCE]] += 25 at that point really

means 100 += 25. What you are looking for is "call by reference"

behavior, and the way to get it is to use one of the Hold*

attributes. In this case you want to first argument of your deposit[]

function to remain unevaluated so the actual symbol "a" is passed into

the function in rather than the value of "a". You'll also need to

change the pattern of the first argument from _Account to _Symbol.

This works how you want:

SetAttributes[deposit, HoldFirst]

deposit[account_Symbol, amount_] := account[[BALANCE]] += amount

In[55]:= deposit[a, 25]

Out[55]= 125

In[56]:= getBalance[a]

Out[56]= 125

-Rob

Nov 4, 2009, 1:43:08 AM11/4/09

to

Erik Max Francis wrote:

> I was experimenting with vaguely OOP-like wrappers around data similar

> to how Twitter.m does things:

>

> http://blog.wolfram.com/2009/04/30/twittering-with-mathematica/

>

> I was experimenting with "mutable objects" and I'm running into a

> scoping problem of some type that I don't understand. Here's some

> sample code creating a wrapper around an "account balance":

>

> In[1]:= {NAME, BALANCE} = Range[2]

>

> Out[1]= {1, 2}

>

> In[2]:= create[name_, balance_] := Account[name, balance]

>

> In[3]:= getName[account_Account] := account[[NAME]]

>

> In[4]:= getBalance[account_Account] := account[[BALANCE]]

>

> In[5]:= deposit[account_Account, amount_] :=> I was experimenting with vaguely OOP-like wrappers around data similar

> to how Twitter.m does things:

>

> http://blog.wolfram.com/2009/04/30/twittering-with-mathematica/

>

> I was experimenting with "mutable objects" and I'm running into a

> scoping problem of some type that I don't understand. Here's some

> sample code creating a wrapper around an "account balance":

>

> In[1]:= {NAME, BALANCE} = Range[2]

>

> Out[1]= {1, 2}

>

> In[2]:= create[name_, balance_] := Account[name, balance]

>

> In[3]:= getName[account_Account] := account[[NAME]]

>

> In[4]:= getBalance[account_Account] := account[[BALANCE]]

>

> account[[BALANCE]] += amount

>

> The deposit function doesn't work, though:

>

> In[6]:= a = create["test", 100]

>

> Out[6]= Account["test", 100]

>

> In[7]:= getBalance[a]

>

> Out[7]= 100

>

> In[8]:= deposit[a, 25]

>

> During evaluation of In[8]:= Set::setps: Account[test,100] in the part

> assignment is not a symbol. >>

>

> Out[8]= 125

>

> In[9]:= getBalance[a]

>

> Out[9]= 100

>

> But here's what I'm confused; if I do what getBalance does manually, it

> works fine:

>

> In[10]:= a[[BALANCE]] += 25

>

> Out[10]= 125

>

> In[11]:= a

>

> Out[11]= Account["test", 125]

>

> The Set::setps error is about Blocks so I suppose I'm running into some

> scoping issue but I don't follow what it is. What am I missing here?

> What's the right way to write getBalance?

>

> In[6]:= a = create["test", 100]

>

> Out[6]= Account["test", 100]

>

> In[7]:= getBalance[a]

>

> Out[7]= 100

>

> In[8]:= deposit[a, 25]

>

> During evaluation of In[8]:= Set::setps: Account[test,100] in the part

> assignment is not a symbol. >>

>

> Out[8]= 125

>

> In[9]:= getBalance[a]

>

> Out[9]= 100

>

> But here's what I'm confused; if I do what getBalance does manually, it

> works fine:

>

> In[10]:= a[[BALANCE]] += 25

>

> Out[10]= 125

>

> In[11]:= a

>

> Out[11]= Account["test", 125]

>

> The Set::setps error is about Blocks so I suppose I'm running into some

> scoping issue but I don't follow what it is. What am I missing here?

> What's the right way to write getBalance?

You are using the formal argument "account" in the manner of a

call-by-reference" parameter. One can emulate that in Mathematica by

making it a held argument.

SetAttributes[deposit, HoldFirst]

Now you have a new problem, which is that the head will not be

recognized as Account (it will be Symbol, because all that is seen

before the rule fires is "a", sans quotes). No big deal, we'll evaluate

it and check the head.

deposit[account_, amount_] /;

Head[Evaluate[account]] === Account :=

account[[BALANCE]] += amount

That should work for the purpose you have in mind.

> Do Mathematica users find Twitter.m's approach to wrapping around

> objects palatable in the first place? (My eventual application is for a

> wrapper around tensor objects where multiple things have to be carted

> around and the normal display of such objects would be far too ungainly

> to be acceptable anyway.)

>

> Thanks.

I'll reread that blog, but I suspect it's one of those things that is

incomprehensible to those past a certain age.

Daniel Lichtblau

Wolfram Research

Nov 10, 2009, 6:03:22 AM11/10/09

to

This is true but here's what's confusing me, and it's obviously a

misunderstanding of how Mathematica treats objects and what object

mutation means in Mathematica (if indeed that's really allowed in any

meaningful sense in Mathematica). If we continue where I left off, I

can't mutate the value of `a` as above, but I _can_ test it against the

global value of `a` with the `===` operator and verify that it's the

same object (repeating just enough of the definitions to get the idea):

In[67]:= {NAME, BALANCE} = Range[2];

create[name_, balance_] := Account[name, balance]

getName[account_Account] := account[[NAME]]

getBalance[account_Account] := account[[BALANCE]]

deposit[account_Account, amount_] := account[[BALANCE]] += amount

In[90]:= a = create["globals", 100]

Out[90]= Account["globals", 100]

In[91]:= isTheSameAsTheGlobalAQ[account_Account] := account === a

In[92]:= x = a

Out[92]= Account["globals", 100]

In[95]:= isTheSameAsTheGlobalAQ[x]

Out[95]= True

So I can verify it's the same object, but I can't mutate it -- that

generates the aforementioned Set::setps error. But doing it manually

with a itself works fine. How come? What is it about Mathematica and

values that I'm not getting? It's obviously something fundamental, but

I haven't encountered it in a book before.

Clearly Mathematica has a more functional approach, so what I'm doing is

naughty anyway. Do I take it that the idea of mutating an object in a

local context and expecting it to have wider-ranging results (as, say,

in other languages like Python or Java or Lisp) is just simply mistaken?

--

Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/

San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis

Can I walk with you / 'Till the day that my heart stops beating

-- India Arie

Nov 10, 2009, 6:10:42 AM11/10/09

to

Okay. I see that since Mathematica is far more functional a language

than other languages that I've used and so what I was trying to do there

was quite alien -- sufficiently so that I really shouldn't try. (In

this particular case, I was just taking a rather typical OOP example and

playing with it in Python, it wasn't central to my question below ...)

>> Do Mathematica users find Twitter.m's approach to wrapping around

>> objects palatable in the first place? (My eventual application is for a

>> wrapper around tensor objects where multiple things have to be carted

>> around and the normal display of such objects would be far too ungainly

>> to be acceptable anyway.)

>

> I'll reread that blog, but I suspect it's one of those things that is

> incomprehensible to those past a certain age.

Well, when I boil down when I'm talking about here it's not so much OOP

per se but rather opaque types, giving the ability to pack lots of stuff

in an object, hide it with a nice face by using Format[..., Standard] :=

...., and then define a bunch of functions that take it at the first

argument and manipulate it.

The context I mentioned above is a tensor library where you don't really

want to see the components of the tensor unless you specifically ask for

it -- a 4-dimensional Riemann tensor, after all, has 4^4 components --

but instead you just want to specify a set of coordinates, a metric

using those coordinates, and then go to town creating and manipulating

those tensors, then crank out specific calculations based on them.

Does that make more sense as being something reasonably Mathematica-ish,

using that approach for type opaqueness?

Nov 11, 2009, 4:27:21 AM11/11/09

to

> So I can verify it's the same object, but I can't mutate it

Help says: "lhs === rhs yields True if the expression lhs is identical to

rhs, and yields False otherwise." That means the two EXPRESSIONS are

identical, not that the two are the same OBJECT.

For instance:

First I set x and y to the same value:

x = f[5]

y = x

f[5]

f[5]

They test identical (SameQ):

x === y

True

Now I change x:

x = 2

2

But y is unchanged, since x and y are different objects:

y

f[5]

Now I define a function:

Clear[f]

SetAttributes[f, HoldFirst]

f[x_] := (x++; Null)

Next I pass x to f, and show the new value of x:

f[x]

x

3

Now look at the value of y, again:

y

Increment::rvalue: 5 is not a variable with a value, so its value cannot

be changed. >>

Do the same again:

y

Increment::rvalue: 5 is not a variable with a value, so its value cannot

be changed. >>

We get exactly the same error message, since y is still f[5].

Test that:

y===f[5]

Increment::rvalue: 5 is not a variable with a value, so its value cannot

be changed. >>

Increment::rvalue: 5 is not a variable with a value, so its value cannot

be changed. >>

True

Yes, y is still f[5], even though the error appears again (once for the

left hand side, again for the right).

Now change f, and show the value of y again.

f = Sin@# &;

y

Sin[5]

Bobby

On Tue, 10 Nov 2009 05:02:59 -0600, Erik Max Francis <m...@alcyone.com>

wrote:

> This is true but here's what's confusing me, and it's obviously a

> misunderstanding of how Mathematica treats objects and what object

> mutation means in Mathematica (if indeed that's really allowed in any

> meaningful sense in Mathematica). If we continue where I left off, I

> can't mutate the value of `a` as above, but I _can_ test it against the

> global value of `a` with the `===` operator and verify that it's the

> same object (repeating just enough of the definitions to get the idea):

>

> In[67]:= {NAME, BALANCE} = Range[2];

> create[name_, balance_] := Account[name, balance]

> getName[account_Account] := account[[NAME]]

> getBalance[account_Account] := account[[BALANCE]]

> deposit[account_Account, amount_] := account[[BALANCE]] += amount

>

> In[90]:= a = create["globals", 100]

>

> Out[90]= Account["globals", 100]

>

> In[91]:= isTheSameAsTheGlobalAQ[account_Account] := account === a

>

> In[92]:= x = a

>

> Out[92]= Account["globals", 100]

>

> In[95]:= isTheSameAsTheGlobalAQ[x]

>

> Out[95]= True

>

> So I can verify it's the same object, but I can't mutate it -- that

> generates the aforementioned Set::setps error. But doing it manually

> with a itself works fine. How come? What is it about Mathematica and

> values that I'm not getting? It's obviously something fundamental, but

> I haven't encountered it in a book before.

>

> Clearly Mathematica has a more functional approach, so what I'm doing is

> naughty anyway. Do I take it that the idea of mutating an object in a

> local context and expecting it to have wider-ranging results (as, say,

> in other languages like Python or Java or Lisp) is just simply mistaken?

>

Nov 11, 2009, 4:30:07 AM11/11/09

to

Hi Erik,

If you really want to do OOP in Mathematica, you may also check out the

package classes.m by Roman Maeder (and of course his books "The Mathematica

Programmer I,II" and "Computer Science with Mathematica"), and the book of

John Gray "Mastering Mathematica" for the detailed discussion of how one can

implement and use OOP in Mathematica.

If all you need is to create and use an ADT (no inhertiance, no

polymorphism),

you can do it relatively easily with UpValues. Here, for example, I define

a type "Pair", with operators <new> and <delete>, getters and setters.

Unprotect[pair, setFirst, getFirst, setSecond, getSecond, new, delete];

ClearAll[pair, setFirst, getFirst, setSecond, getSecond, new, delete];

Module[{first, second},

first[_] := {};

second[_] := {};

pair /: new[pair[]] := pair[Unique[]];

pair /: pair[tag_].delete[] := (first[tag] =.; second[tag] =.);

pair /: pair[tag_].setFirst[value_] := first[tag] = value;

pair /: pair[tag_].getFirst[] := first[tag];

pair /: pair[tag_].setSecond[value_] := second[tag] = value;

pair /: pair[tag_].getSecond[] := second[tag];

Format[pair[x_Symbol]] := "pair[" <> ToString[Hash[x]] <> "]";

];

Protect[pair, setFirst, getFirst, setSecond, getSecond, new, delete];

I beleive that implementing ADT in the above manner lets one avoid the

pass-by-reference problems you mentioned. Note that while definitions are

attached to <pair>, they redefine the action of Dot (.) on their patterns -

this is why we can use the usual OO notation.

Here is how we could use it :

pr = new[pair[]];

pr.setFirst[10];

pr.setSecond[20];

{pr.getFirst[], pr.getSecond[]}

{10, 20}

Creating a list of new pair objects :

pairs = Table[new[pair[]], {10}]

{"pair[430427975]", "pair[430428059]", "pair[430428060]", "pair[430428057]",

\

"pair[430428058]", "pair[430428063]", "pair[430428064]", "pair[430428061]",

\

"pair[430428062]", "pair[430428051]"}

Setting the fields :

Module[{i},

For[i = 1, i <= 10, i++,

pairs[[i]].setFirst[10*i];

pairs[[i]].setSecond[20*i];]]

Checking the fields :

#.getFirst[] & /@ pairs

{10, 20, 30, 40, 50, 60, 70, 80, 90, 100}

#.getSecond[] & /@ pairs

{20, 40, 60, 80, 100, 120, 140, 160, 180, 200}

Here is how you could type-check the code that uses your data type: the

following function, for example, takes a sequence of <pair>-s, sums up

corresponding fields and produces a new pair with fields equal to these

sums. The pattern __pair constitutes a type check.

Clear[sumFields];

sumFields[args__pair] :=

With[{result = new[pair[]]},

With[{sums =

Total /@ Transpose[{#.getFirst[], #.getSecond[]} & /@ {args}]},

result.setFirst[sums[[1]]];

result.setSecond[sums[[2]]];

result]];

With this ADT construction, you will have to remember to explicilty use

<delete> on objects you no longer need, to avoid memory leaks, because the

internal variables <first>, <second> inside Module will not be automatically

garbage-collected by Mathematica (since they are referenced by global

symbols - <pair> in this case). Another thing: since Unique[] is used to

give each instance of our "object" an identity, it is only unique within a

single Mathematica session.

#.delete[] & /@pairs;

One good thing about UpValues is that the names <new>, <delete>,

<setFirst>,<getFirst>, etc are available should you wish to use them in

defining more than one ADT at the same time - the definitions are really

attached to the container (type) name - <pair> in this case.

Hope this helps.

Regards,

Leonid

On Tue, Nov 10, 2009 at 2:03 PM, Erik Max Francis <m...@alcyone.com> wrote:

> Okay. I see that since Mathematica is far more functional a language

> than other languages that I've used and so what I was trying to do there

> was quite alien -- sufficiently so that I really shouldn't try. (In

> this particular case, I was just taking a rather typical OOP example and

> playing with it in Python, it wasn't central to my question below ...)

>

> >> Do Mathematica users find Twitter.m's approach to wrapping around

> >> objects palatable in the first place? (My eventual application is for a

> >> wrapper around tensor objects where multiple things have to be carted

> >> around and the normal display of such objects would be far too ungainly

> >> to be acceptable anyway.)

> >

> > I'll reread that blog, but I suspect it's one of those things that is

> > incomprehensible to those past a certain age.

>

Nov 11, 2009, 4:31:05 AM11/11/09

to

Erik Max Francis wrote:

> Daniel Lichtblau wrote:

>> Erik Max Francis wrote:

>>> I was experimenting with vaguely OOP-like wrappers around data similar

>>> to how Twitter.m does things:

>>>

>>> http://blog.wolfram.com/2009/04/30/twittering-with-mathematica/

>>>

>>> I was experimenting with "mutable objects" and I'm running into a

>>> scoping problem of some type that I don't understand. Here's some

>>> sample code creating a wrapper around an "account balance":

>>> [...hope I'm not snipping too much...]

>

> Okay. I see that since Mathematica is far more functional a language

> than other languages that I've used and so what I was trying to do there

> was quite alien -- sufficiently so that I really shouldn't try. (In

> this particular case, I was just taking a rather typical OOP example and

> playing with it in Python, it wasn't central to my question below ...)

> Daniel Lichtblau wrote:

>> Erik Max Francis wrote:

>>> I was experimenting with vaguely OOP-like wrappers around data similar

>>> to how Twitter.m does things:

>>>

>>> http://blog.wolfram.com/2009/04/30/twittering-with-mathematica/

>>>

>>> I was experimenting with "mutable objects" and I'm running into a

>>> scoping problem of some type that I don't understand. Here's some

>>> sample code creating a wrapper around an "account balance":

>

> Okay. I see that since Mathematica is far more functional a language

> than other languages that I've used and so what I was trying to do there

> was quite alien -- sufficiently so that I really shouldn't try. (In

> this particular case, I was just taking a rather typical OOP example and

> playing with it in Python, it wasn't central to my question below ...)

I'm not sure why this seems alien. People use such constructs in

Mathematica quite often.

> [...]

> Well, when I boil down when I'm talking about here it's not so much OOP

> per se but rather opaque types, giving the ability to pack lots of stuff

> in an object, hide it with a nice face by using Format[..., Standard] :=

> ...., and then define a bunch of functions that take it at the first

> argument and manipulate it.

>

> The context I mentioned above is a tensor library where you don't really

> want to see the components of the tensor unless you specifically ask for

> it -- a 4-dimensional Riemann tensor, after all, has 4^4 components --

> but instead you just want to specify a set of coordinates, a metric

> using those coordinates, and then go to town creating and manipulating

> those tensors, then crank out specific calculations based on them.

>

> Does that make more sense as being something reasonably Mathematica-ish,

> using that approach for type opaqueness?

Yes. I see no reason not to do that in Mathematica. I won't say it is

common, but people do use Mathematica in the way you describe. Often it

is for similar reasons: hide the mess, expose the functionality (that

may not be an entirely accurate paraphrasing of what you describe, but I

think it is not too far from the mark).

Daniel Lichtblau

Wolfram Research

Nov 12, 2009, 6:07:10 AM11/12/09

to

DrMajorBob wrote:

>> So I can verify it's the same object, but I can't mutate it

>

> Help says: "lhs === rhs yields True if the expression lhs is identical to

> rhs, and yields False otherwise." That means the two EXPRESSIONS are

> identical, not that the two are the same OBJECT.

>> So I can verify it's the same object, but I can't mutate it

>

> Help says: "lhs === rhs yields True if the expression lhs is identical to

> rhs, and yields False otherwise." That means the two EXPRESSIONS are

> identical, not that the two are the same OBJECT.

Well, that sure explains that! Obviously pure misunderstanding on my

part, I read something about `===` somewhere along the line that was

mistaken and just carried it forward. Should have double-checked the

(excellent) documentation itself first.

Thanks!

--

Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/

San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis

It is dark in my favorite dream.

-- Aaliyah

Nov 13, 2009, 5:56:55 AM11/13/09

to

Thanks again to everyone for their thoughts.

--

Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/

San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis

They have rights who dare defend them.

-- Roger Baldwin

Reply all

Reply to author

Forward

0 new messages

Search

Clear search

Close search

Google apps

Main menu