In September, last year, I posted here asking your opinions on weak
pointers:
http://compilers.iecc.com/comparch/article/08-09-004
I apologize for not responding to any of them. I'm not sure why I
didn't. (At the time I must have thought a simple 'thank you' response
would not get through moderation.) But the responses were useful!
Thanks! We've decided to keep weak pointers around, if only to give
programmers a tool to break reference cycles. And there are other
uses.
Anyway, we have rethought our pointer system since then, and I would
like some opinions on a new issue.
To catch up: variables in Mist (the programming language) no longer
have reference semantics, as they did in the earliest version. The
"every variable is a pointer" idea seemed in retrospect to lack
elegance and scalability. For example, when copying an array, would we
have copied the pointers within, or the values within? There was no
right answer, since all variables were also pointers.
We have reverted to value semantics now. A pointer is now only a
pointer, with an address as its value. This makes the language more
predictable. We still do not allow pointer arithmetic, nor can you
compare pointers for anything other than (non)equality. We still have
strong and weak pointers. A strong pointer keeps its object alive and
shares ownership with other strong pointers. A weak pointer 'observes'
an object. It can be used to access the object and to test for its
existence. A short example of the syntax follows:
int^ sp <- new 42; // strong pointer to heap allocated integer 42
int` wp <- sp; // weak pointer to the same value
write(wp^); // dereferencing a pointer, writing "42"
sp <- null; // destructs the value 42; this is testable through wp
Ok then. The issue is: do we want to allow 'promotion' of a weak
pointer to a strong pointer? Obviously we want to be able implicitly
cast a strong pointer to a weak pointer. How else could an object
obtain a weak reference? But if we allowed programmers to obtain a
strong reference from a weak one (which is technically possible), the
lifetime of the object would be much more difficult to analyze.
We may want to offer the guarantee that a scoped variable will be
destructed at the end of the scope, while still allowing weak pointers
to it. If we allowed promotion, the object might be 'rescued' by a
strong pointer obtained from a weak pointer.
So the main question would be: Can anyone think of a use-case for
promotion of a weak pointer in which there is no obvious alternative?
I have already gone through some of the basics, like inserting/
removing elements from doubly linked lists (strong pointers left-to-
right, weak pointers right-to-left). There doesn't seem to be a
problem there, and the casting-one-way-only rule seems to fit nicely.
But there are probably things I haven't considered.
Thanks in advance for your reply!
I wasn't in on the previous discussion, but if I had been, I would
have said this:
The term "weak pointer" is a misnomer. Weakness is not a property of
pointers, but rather of locations that hold pointers. It really would
be better to say "weak location".
So you don't "promote a weak pointer to a strong pointer"; you read
the contents of a weak location, which can contain either a pointer or
null.
-- Scott
One reason you may want to promote a weak reference to a strong
reference is under contention from different thread contexts. In fact
where there is contention, the system should *require* promotion
before dereferencing.
Consider:
if (my_weak_ptr != NULL)
my_weak_ptr->do_something();
Here if my_weak_ptr's target is garbage collected in another thread
between the test and when it is used than you are going to dereference
null.
Better to:
my_strong_ptr = my_weak_ptr;
if (my_strong_ptr != NULL)
my_strong_ptr->do_something();
That way the strong reference will provide protection for the critical
section of code.
Enjoy,
Andrew.
--
Andrew Tomazos <and...@tomazos.com> <http://www.tomazos.com>
[In every system I've seen with strong and weak pointers, the pointer
values are all either filled in or not before the program starts. I
suppose there might be race conditions if you do dynamic linking, but
that's a separate issue. -John]
> I wasn't in on the previous discussion, but if I had been, I would
> have said this:
>
> The term "weak pointer" is a misnomer. Weakness is not a property of
> pointers, but rather of locations that hold pointers. It really would
> be better to say "weak location".
>
> So you don't "promote a weak pointer to a strong pointer"; you read
> the contents of a weak location, which can contain either a pointer or
> null.
I'm not sure I understand what you mean. Do you mean conceptually, or
are you talking about an implementation of strong/weak pointers? Note
that I am *not* talking about pointers from the C(++) language, with a
strong/weak wrapper. I'm talking about pointers in a new language we
are designing. In this language, the pointers *are* either strong or
weak.
If you were speaking conceptually (meaning it is relevant for us), I
would like for you to clarify.
Thanks!
> One reason you may want to promote a weak reference to a strong
> reference is under contention from different thread contexts. In fact
> where there is contention, the system should *require* promotion
> before dereferencing.
>
> Consider:
>
> if (my_weak_ptr != NULL)
> my_weak_ptr->do_something();
>
> Here if my_weak_ptr's target is garbage collected in another thread
> between the test and when it is used than you are going to dereference
> null.
>
> Better to:
>
> my_strong_ptr = my_weak_ptr;
> if (my_strong_ptr != NULL)
> my_strong_ptr->do_something();
>
> That way the strong reference will provide protection for the critical
> section of code.
I did not consider threaded applications, mostly because we are mainly
focussing on sequential applications in Mist. But your point remains
valid, nonetheless.
However, I would argue that weak pointer promotion is in this instance
only a workaround for ensuring the isolation of your pair of
operations (testing for null and dereferencing). You did not really
want to keep the object alive. You merely wanted to interact with the
object iff it exists, which should be possible with a weak pointer.
It would perhaps be better if the programmer were able to set and
release a lock against destruction at the location of the object, yet
still use a weak pointer. I have not thought this through in detail,
though.
> [In every system I've seen with strong and weak pointers, the pointer
> values are all either filled in or not before the program starts. I
> suppose there might be race conditions if you do dynamic linking, but
> that's a separate issue. -John]
I'm not sure I'm following you, John. The pointers I'm talking about
can be made to point to other objects during the lifetime of the
program. Their value is not fixed at its beginning.
[Now I'm confused, too. This is an ordinary race condition of the kind
that every parallel program has to handle, and would present the same
issues no matter what kind of pointer it is. -John]
> [Now I'm confused, too. This is an ordinary race condition of the kind
> that every parallel program has to handle, and would present the same
> issues no matter what kind of pointer it is. -John]
Agreed. Andrew simply suggested that one way to avoid the the
destruction of the object (by thread A) between the test and the
access (in thread B) is to first promote the weak pointer in thread B
to temporarily keep the object alive.
It's certainly a way to go. But I believe a locking mechanism
specifically for this purpose would be more elegant. Anyway, it will
be a while before we have to worry about threading. There's still
plenty to do on sequential programming.
> On Jun 16, 12:39 pm, Andrew Tomazos <and...@tomazos.com> wrote:
>> if (my_weak_ptr != NULL)
>> my_weak_ptr->do_something();
> [Now I'm confused, too. This is an ordinary race condition of the kind
> that every parallel program has to handle, and would present the same
> issues no matter what kind of pointer it is. -John]
It seems different, because in this case, the race condition is caused
by the implementation (i.e. the garbage collector), not by the
application.
Say Thread A is doing the above 'if', and Thread B has a pointer X that
points to the same heap object as my_weak_ptr. At the same time as
the above 'if', Thread B sets X to null, and the GC gets triggered
for whatever reason, and the heap object gets collected.
The variable my_weak_ptr is not a shared variable. Thread B didn't
touch it. Thread B didn't touch the heap object, either.
So you wouldn't normally expect to need any locking.
The weak pointer is special, in that it can asynchronously get set to
null, even though no application-level thread modified it. So the
language needs some way to deal with them atomically, and Andrew Tomazos
is suggesting an atomic "convert weak to strong" operation.
Similarly, you could have an operation like "make this weak pointer
strong during the following block of code, then it reverts to weak".
- Bob
I think you should study some prior art. Try and write up a concrete
analysis of the way that the following three weak reference
implementations work:
(1) java.lang.ref.WeakReference (Java)
<http://java.sun.com/javase/6/docs/api/java/lang/ref/
WeakReference.html>
(2) System.WeakReference (C#)
<http://msdn.microsoft.com/en-us/library/
system.weakreference.aspx>
(3) boost::weak_ptr (C++)
<http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/weak_ptr.htm>
Unless you are happy with 'this' becoming null during the execution of a
function (which by the way can be useful in rare cases, but may require a
specific notation with a prototype like "public int myfunction(params)
weak").
imagining your implicit "this" is strong, you can also note that it is what
you _will_ do whatever the case using "my_ptr->function"
because here "->" _always_ promote to strong pointer. so this promotion is
forcefully existing in your language.
promoting to strong by hand before the test "ptr != null" would be just an
explicit way to do it: no new runtime code to implement.
Regards
Armel
I disagree. Weak pointers are inherently racy, so you have to write the
code to cope with that fact. For example,
ptr_copy = my_weak_ptr;
if (ptr_copy != NULL)
ptr_copy->do_something();
Tony.
--
f.anthony.n.finch <d...@dotat.at> http://dotat.at/
FORTIES CROMARTY FORTH TYNE DOGGER: SOUTH VEERING WEST OR SOUTHWEST 5 TO 7,
OCCASIONALLY GALE 8 AT FIRST EXCEPT IN CROMARTY. MODERATE OR ROUGH. RAIN THEN
SHOWERS. MODERATE OR POOR BECOMING GOOD.