OWL Web Language
-
@boomzilla Which scenario are you talking about?
AFAICT the conundrum you're trying to pose only makes sense if you conflate the two. Would you mind clarifying?
-
@wharrgarbl Are you saying that unprotected concurrent access isn't inherently undefined behavior? If so, can you confidently predict what the outcome of the immutable version will be, and that it will be the same every time if you run this code 100 times?
-
@masonwheeler said in OWL Web Language:
@boomzilla Which scenario are you talking about?
AFAICT the conundrum you're trying to pose only makes sense if you conflate the two. Would you mind clarifying?
You first. Put this in terms of my
A
andB
threads, and I suspect you'll answer your own question. I'm not sure what's unclear about what I wrote, so I'm not sure how to clarify:@boomzilla said in OWL Web Language:
The race condition is that one thread (
A
) holds a reference and starts to modify it. At that time, the reference is1
. At that point another thread (B
) takes the reference and the count is incremented to2
. Now threadA
has modified a string with a reference count of2
.
-
@medinoc said in OWL Web Language:
And then you go murder the guy who took a reference to the smart pointer across threads instead of copying it and "sending" the copy.
A lot of theoretical implementation issues can be solved with murder.
-
@masonwheeler said in OWL Web Language:
@wharrgarbl Are you saying that unprotected concurrent access isn't inherently undefined behavior?
There is no unprotected concurrent access in my example with immutable strings.
The resulting string is still unpredictable, yes, but that isn't relevant to the problem being discussed. It could easily be worked around using "foo1 foo2 foo3 foo4" to be concurrently replaced by "bar1 bar2 bar3 bar4".
In my example, the function "replace" will work with a single immutable string all the time. In your mutable string you'll be doing it inplace, with the string changing while it's being processed. These situations often cause buffer overflows, and all types o funny segmentation faults.
-
@boomzilla The problem is that you're only looking at one possible outcome, where the whole point of a race condition, the reason it's called that, is that it's like two people in a footrace: either one could arrive at the finish line first, causing very different results.
@boomzilla said in OWL Web Language:
I'm not sure what's unclear about what I wrote, so I'm not sure how to clarify.
How do you know the scenario you described isn't the intended outcome?
The other possible outcome is that thread B takes the reference first. Then thread A modifies it and, because we're dealing with value semantics here, you end up with two threads with two distinct strings with a refcount of 1.
Immutable version, scenario 1:
Thread A modifies the string, then thread B makes its own copy of it. Both threads now have the modified version.
Immutable version, scenario 2:
Thread B takes the reference, then thread A makes a copy of it and modifies it. Both threads now have distinct strings.
It's the exact same race condition. I don't see how it's possible to explain this any more clearly.
-
@wharrgarbl said in OWL Web Language:
There is no unprotected concurrent access in my example with immutable strings.
The resulting string is still unpredictable, yes, but that isn't relevant to the problem being discussed.
That's the entire point of the problem being discussed!
It could easily be worked around using "foo1 foo2 foo3 foo4" to be concurrently replaced by "bar1 bar2 bar3 bar4".
In my example, the function "replace" will work with a single immutable string all the time. In your mutable string you'll be doing it inplace, with the string changing while it's being processed. These situations often cause buffer overflows, and all types o funny segmentation faults.
I'm quite certain that doesn't happen. I'd have to double-check why, which I can't do as I don't have Delphi installed here on my work system, but if I remember when I get home, I'll set that up and disassemble the output to see what's going on.
-
@masonwheeler said in OWL Web Language:
I'm quite certain that doesn't happen. I'd have to double-check why, which I can't do as I don't have Delphi installed here on my work system, but if I remember when I get home, I'll set that up and disassemble the output to see what's going on.
We're not discussing Delphi strings, we're discussing mason strings. Delphi probably uses some synchronization mechanism.
-
@masonwheeler said in OWL Web Language:
The problem is that you're only looking at one possible outcome, where the whole point of a race condition, the reason it's called that, is that it's like two people in a footrace: either one could arrive at the finish line first, causing very different results.
Well, yeah, I'm looking at the bad outcome.
@masonwheeler said in OWL Web Language:
How do you know the scenario you described isn't the intended outcome?
You're right, I'm assuming that the application isn't relying on bugs to work appropriately.
@masonwheeler said in OWL Web Language:
The other possible outcome is that thread B takes the reference first. Then thread A modifies it and, because we're dealing with value semantics here, you end up with two threads with two distinct strings with a refcount of 1.
Yes, and based on COW semantics, that's what you'd expect. So you're really confused and spend a lot of time trying to figure out why your program fails in a seemingly impossible way.
@masonwheeler said in OWL Web Language:
It's the exact same race condition. I don't see how it's possible to explain this any more clearly.
You're still confusing the immutability of the string with the immutability of another object that's holding a reference. That's the source of your confusion.
-
@masonwheeler I just found some references stating that Delphi strings are NOT threadsafe.
Page 102 of the book above, Google let me see that in the preview.
-
@masonwheeler said in OWL Web Language:
It's the exact same race condition. I don't see how it's possible to explain this any more clearly.
Now, what are the consequences? If
B
picks up the string and starts reading from it whileA
is still modifying it then you can have some real problems. That's the consequence of this race condition. In the case of immutable strings, you always at least get a good string that's safe to use.
-
@boomzilla Thread B doesn't even need to create a new reference or increment the refcount. COW was never intended as a thread-safety mechanism.
-
-
@boomzilla said in OWL Web Language:
You're still confusing the immutability of the string with the immutability of another object that's holding a reference. That's the source of your confusion.
No, I understand that part very clearly. You're confusing immutable reference types with COW value semantics on reference types. Conflating the two in order to "demonstrate" that a race condition exists when you do something that looks the same but is handled very differently is the source of your confusion.
-
@wharrgarbl said in OWL Web Language:
@boomzilla Thread B doesn't even need to create a new reference or increment the refcount. COW was never intended as a thread-safety mechanism.
Right. I was just riffing on @masonwheeler talking about how COW doesn't need any sort of lock to work with multi-threading.
@masonwheeler said in OWL Web Language:
You're confusing immutable reference types with COW value semantics on reference types.
In what way? I thought I was comparing the two.
-
@boomzilla said in OWL Web Language:
@masonwheeler said in OWL Web Language:
...which is completely different from the race condition that @wharrgarbl is talking about.
I don't realy care what he's talking about.
@masonwheeler said in OWL Web Language:
I was pointing out that if you set up the equivalent scenario with immutable strings, you get the exact same race condition.
I was just pointing out that COW can fail in a multi-threaded system in a way that immutable strings cannot.
Immutable strings can fail there as well: There is only one reference, one thread replaces it while another thread copies it. The thread replacing the reference may decrement the reference count (to zero) before the copying thread increments it. Which may lead to resources being freed.
The details are different but the erroneous situation leading to the problem is the same.
-
@pleegwat said in OWL Web Language:
Immutable strings can fail there as well: There is only one reference, one thread replaces it while another thread copies it. The thread replacing the reference may decrement the reference count (to zero) before the copying thread increments it. Which may lead to resources being freed.
Yes, that all depends on the garbage collection and assumes that there's no synchronization for acquiring / destroying things. I guess the big point is that in a multithreaded environment you gotta have that sort of thing, contra @masonwheeler.
-
@boomzilla Yes, in a proper high level language, I expect that when one thread copies a simple class member (be that an integer, a string, or a reference to a different class) while another thread is writing/replacing that member, then the copying thread gets either the old value or the new one. Doing that without locking all the time is an annoyingly complex problem which the high-level language should be saving you from.
-
@pleegwat said in OWL Web Language:
Immutable strings can fail there as well
Without any synchronization control, mutable strings could cause all sorts of undefined behavior, like buffer overflows, and whatnot.
Imagine that your string concatanation internally resize it's buffer with a realoc like this:
string_object.buffer = realloc(newsize);
memcpy(string_object.buffer + position, added_data, added_data_size);Other thread may be writing at the old memory position of string_object.buffer, or depending of the old size of the buffer to do something, and now it will overwrite memory it shouldn't. And your program would corrupt it's heap.
-
@wharrgarbl That's not fundamentally worse than the use-after-free in my immutable example.
-
@pleegwat said in OWL Web Language:
@wharrgarbl That's not fundamentally worse than the use-after-free in my immutable example.
Your example doesn't make sense, because no garbage collector works like that, and it's the COW strings that do reference counting.
-
Some of you are talking shite. I don't know who, as I don't do anything this low level, nor do I care which of you swinging e-peen is actually right, because none of this is relevant to mocking yet another thing that Computing has given us that doesn't need to exist.
-
@arantor said in OWL Web Language:
yet another thing that Computing has given us that doesn't need to exist.
Immutability?
I've always loved the way John Hughes completely dismantled the "immutable is good" nonsense, in a pro-FP paper to boot!
Such a catalogue of “advantages” is all very well, but one must not be surprised if outsiders don’t take it too seriously. It says a lot about what functional programming is not (it has no assignment, no side effects, no flow of control) but not much about what it is. The functional programmer sounds rather like a medieval monk, denying himself the pleasures of life in the hope that it will make him virtuous. To those more interested in material benefits, these “advantages” are not very convincing.
Functional programmers argue that there are great material benefits - that a functional programmer is an order of magnitude more productive than his conventional counterpart, because functional programs are an order of magnitude shorter. Yet why should this be? The only faintly plausible reason one can suggest on the basis of these “advantages” is that conventional programs consist of 90% assignment statements, and in functional programs these can be omitted! This is plainly ridiculous. If omitting assignment statements brought such enormous benefits thenFORTRANJava programmers would have been doing it for twenty years.(The paper was written in 1984, back when FORTRAN was a big deal. Changing one word for better modern context.)
-
@masonwheeler no, you pedantic little shit, the topic that this topic was actually about: the OWL language that is JavaScript like syntax transpiled down to PHP.
I am tired of seeing you pendant shit to death, which is hilarious on a forum that thrives on pendantry. There are limits, you know?
-
@arantor
pedantic_real_dickweedery
???
-
@boomzilla exactly, it's way too much dickweedery to have to scroll through when there's shit to make fun of instead.
-
@arantor let's get back to wtf_real_topic
-
@wharrgarbl So. Compiling Javascript-ish PHP-ish pidgin to PHP. What a ridiculous idea!
-
@masonwheeler there, wasn't that more fun than spending over a hundred posts arguing back and forth about thread safety?
-
@arantor Not particularly.
-
@masonwheeler it's just so tiring watching you try to out pedant everyone else, all the time, whether you're right or not because god forbid you could ever be wrong about something. Not everyone wants to be reminded of your... genius.
-
@arantor said in OWL Web Language:
Not everyone wants to be reminded of your... geniuos.
That's true, but some of us are amused by it.
-
@boomzilla said in OWL Web Language:
That's true, but some of us are amused by it.
Can only stomach so much at a time, you know?
-
@boomzilla said in OWL Web Language:
Yes, that all depends on the garbage collection and assumes that there's no synchronization for acquiring / destroying things.
Or you do an entire family of CoW structured types that all can be handled that way with minimal locking, but where you need more complex locking when you access them via a reference from an in-place-modifiable type. That'd work, and the CoW types would have the (interesting and nice) property of being loop-free provided they can't hold strong references to modifiable types; you can't put a CoW instance inside itself, either directly or indirectly, and that makes reference counting a perfect and efficient lifespan management system. (They can safely hold weak references to modifiable types.)
But threads really stink everything up. Locking and mutexes are exactly what is recommended for excellent reasons, or cloning on inter-thread message transmission (for those who like their thread semantics to be message based; I'm definitely of that persuasion).
-
So, anyways, transpiling, amirite?
-
All I can think of while skimming that thread is:
$ aptitude -h aptitude 0.6.8.2 Usage: aptitude [-S fname] [-u|-i] aptitude [options] <action> ... [...] This aptitude does not have Super Cow Powers.
-
@alexmedia said in OWL Web Language:
After going through OWL's documentation I've gotten a better understanding of what a LockString is: it's a data type for parametrised strings. Think of it as a
SqlCommand
and its parameters collection.Turns out that this has been in .NET since v4.6:
And the Entity Framework devs decided to use it. And due to compiler peculiarities, you'll introduce a SQL injection vulnerability under some circumstances.
-
Meanwhile, it looks like OWL has been renamed to THT...
-
@alexmedia Tenminste Houdbaar Tot?
-
@pleegwat My thoughts exactly. 😂