OWL Web Language
-
@blakeyrat said in OWL Web Language:
If you join the rest of us in the 21st century and use Razor syntax, it's not too bad.
That's what I use in MVC. Still have C# in my HTML. Not much, true, as I design models properly and try not to use the ViewBag where I can. but still, there's the odd loop or conditional.
-
@blakeyrat said in OWL Web Language:
I really don't get what you mean by "muppets" here
-
@dkf pretty much. It's like Swedish Chef does spaghetti code.
-
@dkf said in OWL Web Language:
Copy-on-write semantics would also work, but that's really not how C# (andJava too) rolls, and would be quite awkward to graft on now, as doing it efficiently requires a decision that is annoyingly complex in a multi-threaded environment. (You really don't want to increase the number of locks in use and the alternatives are also quite expensive given that there's usually a lot of strings about.)
???
There are a few million Delphi developers who would beg to differ. There's nothing particularly complex or lock-ful about COW semantics based on an atomic increment/decrement of the reference count.
-
@wharrgarbl said in OWL Web Language:
thread-safe mutable strings have poor performance because of all the locking
What locking? Seriously, where did everyone get this idea from? If you use an atomic increment/decrement of the ref count, there is no lock to hold, and 99.99% of the time there isn't even a bus-level lock taking place. Modern CPUs have been smart enough to not need it unless the value being incremented is currently in the cache of more than one core for a long time now.
-
@masonwheeler said in OWL Web Language:
If you use an atomic increment/decrement of the ref count, there is no lock to hold, and 99.99%
Not enough if the string is mutable like I said
-
@wharrgarbl ...huh?
-
@masonwheeler all you said is only valid for immutable strings
-
@wharrgarbl no, it's not even necessary for immutable strings. COW semantics only apply when things are being written to; it's right there in the name!
-
@masonwheeler OK.
Take
This is a mutable string
as a mutable string.
Thread 1 wants to change it toThis is a notable string
Thread 2 wants to change it toThis is a ratable string
There's no locking.What's the output?
-
@raceprouk said in OWL Web Language:
@masonwheeler OK.
Take
This is a mutable string
as a mutable string.
Thread 1 wants to change it toThis is a notable string
Thread 2 wants to change it toThis is a ratable string
There's no locking.What's the output?
Thread 1 notices the refcount is greater than 1, makes its own copy of the string, changes it.
Depending on when it starts,- either thread 2 makes its own copy while thread 1 is making its (yeah, it wastes an allocation and copy, since the original ends up freed despite not being modified)
- or thread 2 starts after thread 1 has made its copy, so it notices the refcount is one, and modifies its string in-place.
-
@medinoc And when the copy a thread made is written back to the original location, what happens then?
Can you offer a cast-iron guarantee the output won't be either
This is a natable string
orThis is a rotable string
?
-
@raceprouk said in OWL Web Language:
@medinoc when the copy a thread made is written back to the original location
Why would that even happen? That's not how COW works. Copies are only spawned, never merged.
-
@medinoc Then what's the difference between mutable and immutable strings when everything is COW?
-
@raceprouk The whole copying thing is skipped when there's only one reference.
Oh, and things become fun when the smart pointer itself is referenced from multiple places (COW string copies are thread-safe, but the smart pointers themselves are not IIRC -- though they could possibly be with the right lock-free algorithms).
-
@medinoc It seems to me that using COW with mutable strings creates more problems than it solves.
-
@raceprouk @masonwheeler C++ stopped doing COW because of it's bad performance:
-
@wharrgarbl You'll have to do better than to cite a language infamous for bad design decisions.
-
@raceprouk said in OWL Web Language:
@medinoc Then what's the difference between mutable and immutable strings when everything is COW?
What COW means is that it works like this:
myString = "Hello, World!"; // refcount = 1 myString2 = myString; // refcount = 2. No copy necessary myString2[0] = 'J'; //string gets copied and modified // both now have refcount = 1
The difference between mutable and immutable strings is that that last operation is not legal at all in C# or Java.
-
@masonwheeler And is there a benefit?
-
@raceprouk There is if you're doing work that needs to mess around with strings like that. Otherwise you find yourself having to do the much heavier work of loading the string into a char array or a string builder object, changing things there, then instantiating a new string from it--multiple copies instead of just one.
-
@masonwheeler If you're doing that much string manipulation, you should either be starting with a string builder class, or seriously rethinking your implementation.
-
@raceprouk Why?
-
@masonwheeler Because there's almost certainly a better way to do it.
-
@raceprouk If so, the burden of proof is on you to demonstrate what it is. COW based on atomic reference counts has a long, solid track record. It works, it's guaranteed not to cause the sort of corruption you mentioned, and it doesn't cause performance problems due to locks because there are no locks. How do you improve on that?
If I may point something out: you seem to be operating from a perspective that immutability is good by default, at least in this particular case. I haven't drank that kool-aid, so attempting to appeal to arguments based on that presumption will get you nowhere.
-
@masonwheeler Equally, I've yet to see a convincing argument that mutable strings convey benefits that outweigh the drawbacks.
-
@raceprouk What drawbacks?
-
@masonwheeler said in OWL Web Language:
COW based on atomic reference counts has a long, solid track record
So why both C# and C++ avoided them? What popular programming language has it implemented in a fast and thread-safe way?
-
@masonwheeler said in OWL Web Language:
@raceprouk What drawbacks?
Not guaranteed thread-safe, less open to optimisations, potential for unexpected side-effects, can't be used to safely share internal state, stuff like that. All issues that don't affect immutable strings.
-
@wharrgarbl said in OWL Web Language:
So why both C# and C++ avoided them?
C#, because Java did it that way and they wanted to attract Java programmers. (Most of the problems with C#, especially the ones that have been around since the beginning, can be traced back to this.)
C++, heaven only knows. I don't call it the worst programing language ever to be taken seriously for nothing; almost nothing about the language makes sense when you look at it in a wider context.
What popular programming language has it implemented in a fast and thread-safe way?
Delphi's not the only example, but it's the one I'm most familiar with.
-
@raceprouk said in OWL Web Language:
Not guaranteed thread-safe,
Wrong, as has been demonstrated above.
less open to optimisations,
How so?
potential for unexpected side-effects,
Such as what? (This feels like a restatement of your first, incorrect assertion.)
can't be used to safely share internal state
Please elaborate.
-
@masonwheeler said in OWL Web Language:
@raceprouk said in OWL Web Language:
Not guaranteed thread-safe,
Wrong, as has been demonstrated above.
Mutable strings need all sorts of guards to be thread-safe, be they locks, semaphores, or refcounts. Immutable strings, however, are thread-safe by definition.
@masonwheeler said in OWL Web Language:
less open to optimisations,
How so?
Duplicated immutable strings (bad practice, I know) can be safely replaced with a single immutable instance, reducing compiled size. And that's just one of many optimisations that can only be applied to strings (and other data structures) guaranteed not to change. I would list all of them, but you can do some work for a change and look here.
@masonwheeler said in OWL Web Language:
potential for unexpected side-effects,
Such as what? (This feels like a restatement of your first, incorrect assertion.)
Again, I refer you to this excellent resource.
@masonwheeler said in OWL Web Language:
can't be used to safely share internal state
Please elaborate.
As always, you can find everything you need here.
Maybe if you spent as much time learning as you do arguing, you'd actually become a decent developer.
-
@medinoc said in OWL Web Language:
Thread 1 notices the refcount is greater than 1,
And now you've either got locking of some form or you have a race condition as you're trying to determine whether two threads are sharing some information when you've not started from a position with clear-enough semantic constraints to prove it one way or the other. Toby Faire, there's a bunch of ways of doing the locking, some of which are much cheaper than others, but the requirement for the threads to agree on whether they are sharing the information is at the core of the difficulty (and if you get it wrong, you either get write-write hazards or you duplicate lots more information than you want to, which is time- and space-costly).
-
@wharrgarbl said in OWL Web Language:
What popular programming language has it implemented in a fast and thread-safe way?
It's highly efficient in a single thread, but sharing across multiple threads destroy the efficiency.
-
@masonwheeler said in OWL Web Language:
Wrong, as has been demonstrated above.
COW mutable strings are thread-safe, but immutable ones are thread-safer. The following code could write gibberish or fire an exception if the cowstring is modified mid-loop:
for (int i = 0; i < cowstring.length; i++) { Console.Write(cowstring[i]); }
You would need a lock to make this work with mutable strings.
-
@raceprouk said in OWL Web Language:
Duplicated immutable strings (bad practice, I know)
Technically, you sometimes duplicate them because the cost of deduplicating can be higher than the cost of having several copies of the same string.
-
@dkf To avoid paging memory and stuff like that?
-
@wharrgarbl That code should be fine because it holds at least one reference to
cowstring
while the loop is running.
-
@dkf it isn't really mutable if the change made in another insance doesn't reflect on mine, is it?
-
@raceprouk said in OWL Web Language:
To avoid paging memory and stuff like that?
Sometimes you get strings from sources like files or network sockets. They could be deduped on creation, but most of the time you shouldn't bother.
-
@wharrgarbl said in OWL Web Language:
it isn't really mutable if the change made in another insance doesn't reflect on mine, is it?
You probably shouldn't be thinking too much about instances once you're using CoW, since that actually eliminates instance-identity. With CoW, if things look the same they are the same, and the operational semantics of modifiers are that they always return a new copy of the value that you bind to the name (with optimisation for when you're the only holder of a reference). The loop you showed has no modifiers in it, so nothing could happen behind its back; if such modification were possible, there would be a notion of identifier that relates to the thing which is modified (e.g., a memory address or something like that).
-
@dkf I got confused. I think the main reason C++ is avoid the COW is the cost of keeping the reference count.
Does this look like a fast or light thing?
-
-
@dkf said in OWL Web Language:
@medinoc said in OWL Web Language:
Thread 1 notices the refcount is greater than 1,
And now you've either got locking of some form or you have a race condition as you're trying to determine whether two threads are sharing some information when you've not started from a position with clear-enough semantic constraints to prove it one way or the other.
If the refcount is one, you know no other thread (no other anything, really) has a reference, because in that case the refcount would be at least two. Therefore, nothing other than you can increase this refcount, so there's no race condition possible.
-
@wharrgarbl said in OWL Web Language:
@dkf I got confused. I think the main reason C++ is avoid the COW is the cost of keeping the reference count.
Does this look like a fast or light thing?
It could be.
-
-
@raceprouk said in OWL Web Language:
Mutable strings need all sorts of guards to be thread-safe, be they locks, semaphores, or refcounts.
In other words, once you add a refcount, they're threadsafe too, and so your argument has no merit.
Immutable strings, however, are thread-safe by definition.
And also far less useful by definition.
@masonwheeler said in OWL Web Language:
Duplicated immutable strings (bad practice, I know) can be safely replaced with a single immutable instance, reducing compiled size.If you're talking about compiled size, then you're talking about string literals in the codebase, and there's nothing at all stopping the same compile-time optimization from being applied, whether the runtime implementation of the strings are mutable or immutable.
And that's just one of many optimisations that can only be applied to strings (and other data structures) guaranteed not to change. I would list all of them, but you can do some work for a change and look here.
Yeah, no. That's not how it works. You're the one making claims here; the burden of proof is on you to back them up.
Again, I refer you to this excellent resource.
As always, you can find everything you need here.
In other words, "I got nothing but vague insinuations and FUD." I thought as much.
Maybe if you spent as much time learning as you do arguing, you'd actually become a decent developer.
-
@dkf said in OWL Web Language:
@medinoc said in OWL Web Language:
Thread 1 notices the refcount is greater than 1,
And now you've either got locking of some form or you have a race condition as you're trying to determine whether two threads are sharing some information when you've not started from a position with clear-enough semantic constraints to prove it one way or the other. Toby Faire, there's a bunch of ways of doing the locking, some of which are much cheaper than others, but the requirement for the threads to agree on whether they are sharing the information is at the core of the difficulty (and if you get it wrong, you either get write-write hazards or you duplicate lots more information than you want to, which is time- and space-costly).
There is no lock involved in atomic operations on an integer. I explained this way up there. ^^^^^
Even in the sense where an atomic operation can theoretically involve a (very brief) bus lock at the hardware level, in the vast majority of cases this does not happen because it's only necessary when two cores have copies of the same data in their cache at the same time.
-
@medinoc said in OWL Web Language:
If the refcount is one, you know no other thread (no other anything, really) has a reference, because in that case the refcount would be at least two.
That really doesn't follow simply except possibly in the case where Thread A gives a reference to the string to Thread B while still holding on to its own version. In a more general threading pattern, it's really hard to know how many references there actually are unless you apply some sort of locking so that reads and writes to the reference count (and hence decisions based on those reads and writes) are guaranteed to be correct. There are expensive ways to do that, and there are very expensive ways to do that. Oh, and there are also wrong ways to do it. ;)
With threads, especially on a multicore system, it's safer to assume that the computer hates you and is out to get you in as subtle a way as possible.
-
@wharrgarbl said in OWL Web Language:
@masonwheeler said in OWL Web Language:
Wrong, as has been demonstrated above.
COW mutable strings are thread-safe, but immutable ones are thread-safer. The following code could write gibberish or fire an exception if the cowstring is modified mid-loop:
for (int i = 0; i < cowstring.length; i++) { Console.Write(cowstring[i]); }
You would need a lock to make this work with mutable strings.
No. No no no no. For the purpose of this discussion, can we please all just drop the world "lock" from our vocabulary entirely. There is no lock. There is no need for a lock. Anyone who tells you otherwise simply doesn't know what they're talking about.
In this scenario, if some other thread tried to modify it, COW semantics means guaranteeing that it makes a copy first, and then modifies that copy. This one that we're iterating here remains unchanged.