C++ with automatic garbage collection = C#
-
PIEBALDconsult wrote:
this one's better
better for what ? what are you trying to prove ? i've never said GC in MS's C# package isn't provided by the CLR. i've always said that GC is an intrinsic part of C#: that C# requires it; that it is part of what makes C# the language that it is. the specifics of MS's implementation are utterly irrelevant to what i've been saying in this thread.
Oh, then we're in violent agreement... but someone said it was...
-
Chris Losinger wrote:
GC is part of C# the same way vtables are part of C++. RegEx is an add-on in both
Nitpicking, one could say that is true. In the real world, C# doesn't really exist apart from the .NET framework. It's a bit like people assuming that MFC is part of C++, the difference is that in the C# world, there's no real world opposing viewpoint, no version of C# for which it's not true.
Christian Graus - Microsoft MVP - C++ "I am working on a project that will convert a FORTRAN code to corresponding C++ code.I am not aware of FORTRAN syntax" ( spotted in the C++/CLI forum )
Christian Graus wrote:
Nitpicking, one could say that is true. In the real world, C# doesn't really exist apart from the .NET framework. It's a bit like people assuming that MFC is part of C++, the difference is that in the C# world, there's no real world opposing viewpoint, no version of C# for which it's not true.
Not really. I don't believe that anyone would claim that the C# keyword "partial" is part of a library. It completely and solely part of the language. Conversely you can't do regexes in C, C++, java or C# without a library. Matter of fact you can't do anything practical at all in C, C++, java or C# without a library. That isn't true of Perl. Both regexes and quite a bit of other functionality which the other languages lack is supported directly by the language itself. Yet there are a wide variety of libraries for it some of which are part of the "definition" of language itself. And I don't believe the Forth language isn't even Turing complete without a library. So it is certainly relevant to discuss whether a language supports something or not directly. Particularly when that is exactly what the discussion is about.
-
what's wrong with this one[^]? although, i believe that the well designed C++ program should extremely rarely exhibit problems with memory issues. The problem is that many devevelopers still write C using C++ compilers, so they malloc/free or new/delete bunch of stuff. I don't see why anyone would allocate memory for an array on the heap if there is std::vector. why would you explicitly delete something if you have std::auto_ptr or some smart pointer implementation (e.g. boost::shared_ptr)? Of course, i am aware that there are situations where you have to go 'classic' way, but that is minority, IMO.
-
Your simplification fails to grasp several key concepts that distinguish C++. I will just highlight one of these, because it is my favourite concept (and arguably the cornerstone to C++' success). I am speaking of templates. Yes, I know that C# has generics but these have not much in common with C++' powerful concept. C++ templates allow the implementation of very high abstraction data models and algorithms without any runtime penalty whatsoever! Take a look at any book on algorithms. Chances are, the examples are implemented in Java (unless, of course, you are reading Knuth, who, for reasons best known to himself, treats us to MIX). Now, these example codes usually practice a very high level of abstraction and present the concepts in a wonderfully concise way (once we overlook the shortcomings of Java's syntax). But, these books have a serious drawback: They trade abstraction for performance. Unfortunately, this trade-off is still (and will be for years to come) absolutely unacceptable in many computing areas. My own domain is bioinformatics and here the performance/abstraction trade-off of languages such as C#, VB or Java are clearly out of question. Templates in C++ offer the same degree of abstraction – in fact, the STL is a textbook example of abstraction and surpasses anything .NET or Java can muster – and the performance penalty (on modern compilers) equals zero. Good C++ compilers produce code having the same performance as hand-coded assembler routines, while using high abstraction. Stroustrup gives a very good example of the power of templates by comparing C++' std::sort function to qsort from C. Surprisingly, std::sort outperforms qsort even when their implementations are conceptually identical. This is due to the fact that qsort has to call a function pointer in order to compare elements. C++ achieves the same genericity through templates and a function object. This function object call can be inlined most of the time, eliding any runtime overhead. I have to address one other issue, though (because it figures in your thread title). C++ has no garbage collection for very good reasons. For those interested in details, I can advise looking up the RAII idiom and C++' way of treating objects as stack-located values most of the time (rather than working on pointers to the heap).
KLMR wrote:
Unfortunately, this trade-off is still (and will be for years to come) absolutely unacceptable in many computing areas.
Presumably you mean as a absolute count rather than in comparison to all software fields. Because in comparison performance problems causes by data structure layout itself in all of software is so small that it is probably unmeasurable. It would certainly be insignificant.
KLMR wrote:
and the performance penalty (on modern compilers) equals zero.
You are claiming that data constructs in C++ have a zero cost? That is incorrect. Certainly chosing the wrong one can impact the application. And if a particular construct is a bottleneck, which your other comments suggest that you always see, then considering a custom implementation based on knowledge of the actual data and flow can provide a performance improvement over the generic types - which again suggests that there is a cost.
KLMR wrote:
I have to address one other issue, though (because it figures in your thread title). C++ has no garbage collection for very good reasons. For those interested in details, I can advise looking up the RAII idiom and C++' way of treating objects as stack-located values most of the time (rather than working on pointers to the heap).
As far as I can tell both of those assertions are wrong. In terms of original creation of C++ garbage collection probably wasn't considered at all. That would be the reason for not having it. Another reason would have been because C didn't have it. Other than that it is like many other additional features in C++, it one wants it then one can add it. As Stroustrup says.... http://www.research.att.com/~bs/bs_faq.html#garbage-collection[^] Secondly exactly what source leads you to believe that "most" value entities in C++ live on the stack versus the heap? And more importantly what makes you think that is the case for objects versus primitive types? (I don't really consider the consideration of such things as for loop index variables as valid candidates for this since no one is going to ever create those on the heap anyways.)
-
Fernando A. Gomez F. wrote:
Christian Graus wrote: The C# team says they are aiming to make the language as easy as possible, which is the exact opposite of the goal of the C++ team ( make it as powerful as it can be ). That's why I don't like C#. IMO they are creating a monster with the language. As an example, do the yeild return thing adds power? No. But it makes it easy. It reminds me of all this keywords they added to VB6 (not comparing both languages though). They are just making it fancier, instead of giving power to the programmer.
What about anonymous functions and LINQ? Those do give more power, don't they?
I am askin' myself !!! what I do need tones of libraries and spaghetized frameworks to open a file or a socket or a stream or to write some code? I dont. C++ was made by THE ONE for THE ONE. C# was made by the ONES for the OTHERS that's why it wont stand a chance to C++. I don't say C# does not have it's buddies but they will leave-it as soon next language will be invented by some Mammoth company. They already know that couse' they have been to so many ...VB, Java, and now C# and C(bemol)..who knows...
-
Stroustrup was asked when Java came out what he thought of GC. His core answer was that GC would have killed C++, because of performance issues ( which may have been more real with the speed of processors then, than now ). There are a LOT of differences between C++ and C#. C++ has a better standard library, but C# offers support for things that C++ does not, such as regex. Yes, you can add those, I'm talking core language here. If anything, I think it's a shame C# looks like C++, when it's really very different in many ways.
deostroll wrote:
The result of this is that you are being pressurized, unnecessarily; or worse the customers themselves pressurizing you, unnecessarily!
Really, the issue is that your client has no idea how long software takes, and a strong idea of when they want it. Explain the development triangle to them. Features, time, reliability. You can have two. Tell me which one to sacrifice to get the other two done.
deostroll wrote:
Given indefinite time I believe developing applications in c++ would result in robust applications.
Given *reasonable* time, C++ results in robust applications.
Christian Graus - Microsoft MVP - C++ "I am working on a project that will convert a FORTRAN code to corresponding C++ code.I am not aware of FORTRAN syntax" ( spotted in the C++/CLI forum )
I am askin' myself !!! what I do need tones of libraries and spaghetized frameworks to open a file or a socket or a stream or to write some code? I dont. C++ was made by THE ONE for THE ONE. C# was made by the ONES for the OTHERS that's why it wont stand a chance to C++. I don't say C# does not have it's buddies but they will leave-it as soon next language will be invented by some Mammoth company. They already know that, 'couse they have been to so many prior' ...VB, Java, and now C# and C(weak)..who knows...
-
I agree to this extent: if you can get a team of individually near-perfect programmers who work even better together, C++ is the way to go. The control it gives you is not matched in any of the other .NET development environments. However, in the real world...back in 1994 my former boss and at-that-time client asked me what language to use for his new employee benefits administration system. Because he and I had worked together for six years on megabytes of codes written in C, he was surprised when instead of C/C++ I recommended Visual Basic. Naturally, he asked why. I replied, "Because they're cheap and easily disposed." Languages for the elite must be programmed by the elite, and the elite are always in short supply. Granted, with the right three people I could outperform any ten basic coders, but with three basic coders and me writing specs and all of us reviewing code and tests I can generate a working implementation very quickly. This is the primary delivery criterion for business software, as changes in the needs of the business require rapid delivery of changes in the software. It stands as a corollary that any really life-critical system is built in C/C++ or some other language that offers equal control of the programming environment, and it is written only after a great deal of thought has gone into the initial design and the design of any new releases. It all depends on the priorities you are required to recognize. Christopher P. Kile "Nothing is wasted if you keep looking for another use for it."
I think you've got a good grasp of the situation. In a way, it's interesting for me to read threads like this . I am not a professional programmer. What I am is a professional currency trader. All programming I do, and believe me I do a lot, is to that end. So I read these conversations...'this is better than that...my brain is bigger than yours' with a bit of amusement. The bottom line is that software is a tool, period. The software is the servant, not the master. BW ------------------------------------------------------ The natural state of man is trust, not skepticism.
-
Zdeslav Vojkovic wrote:
I don't see why anyone would allocate memory for an array on the heap if there is std::vector.
And where exactly does the std:vector live?
vector's storage does live on heap, however, vector itself usually lives on stack (of course, depending on how you use it), so its destruction is deterministic, and that is what is important here. From your other posts, i believe you are aware of RAII idiom, which is a very powerful kind-of-replacement for GC (yes, i am aware of differences), and more generic (because, unlike GC, with RAII you can also handle other resources, like DB connections, GDI objects, etc). the point here is that, if you use STL (and/or some extensions) properly, you don't need GC in C++ for most tasks, and need for GC is the topic of this thread.
-
Christian Graus wrote:
The C# team says they are aiming to make the language as easy as possible, which is the exact opposite of the goal of the C++ team ( make it as powerful as it can be ).
That's why I don't like C#. IMO they are creating a monster with the language. As an example, do the
yeild return
thing adds power? No. But it makes it easy. It reminds me of all this keywords they added to VB6 (not comparing both languages though). They are just making it fancier, instead of giving power to the programmer. However, I wish the C++ library had more features. A GUI, for example, would be very nice. And XML and networking support. I know that the main goal is to make it portable, thus there may be devices that couldn't support this features. But what the hell, for these cases, they don't have to fulfill the standard (e.g. Embedded VC++ 3 didn't support exception handling). Any way, I'm still looking forward the next version of the standard.
Hope is the negation of reality - Raistlin Majere
Well, I tend to disagree on your point. You could use yield for adding power to C# that is not there in C++. Like LINQ capabilities, it's the support for a functional operator called "call-cc" (Call Current continuation), available in SCHEME a functional language. Suppose you need to traverse a tree and do something with it (print it in-order for instance). You could use a producer-consumer paradigm that keeps the function-stack low, thus memory use is reduced, but otherwise you have a very simple code to read. Something like: delegate ProducerFn; delegate ConsumerFn; public bool Producer(TreeNode t, delegate ConsumerFn) { foreach(TreeNode childNone in t.ChildNodes) { return yield ConsumerFn(t.left, Producer); } } public void Consumer(TreeNode t, delegate ProducerFn) { string str = String.Format(t.ToString()); yield ProducerFn(t, Consumer); } Well since this code will not work (yet) you only get the idea, but I will complete it later on. However, there's a good article for using yield at MSDN which you can see at the Visual Studio IDE as a suggested articles. If you execute and step over it, you may see these advantages. "If All you have is an hammer everything looks like a nail." -BARUCH's OBSERVATION, Murphy law bpsm74@sapo.pt
-
KLMR wrote:
Unfortunately, this trade-off is still (and will be for years to come) absolutely unacceptable in many computing areas.
Presumably you mean as a absolute count rather than in comparison to all software fields. Because in comparison performance problems causes by data structure layout itself in all of software is so small that it is probably unmeasurable. It would certainly be insignificant.
KLMR wrote:
and the performance penalty (on modern compilers) equals zero.
You are claiming that data constructs in C++ have a zero cost? That is incorrect. Certainly chosing the wrong one can impact the application. And if a particular construct is a bottleneck, which your other comments suggest that you always see, then considering a custom implementation based on knowledge of the actual data and flow can provide a performance improvement over the generic types - which again suggests that there is a cost.
KLMR wrote:
I have to address one other issue, though (because it figures in your thread title). C++ has no garbage collection for very good reasons. For those interested in details, I can advise looking up the RAII idiom and C++' way of treating objects as stack-located values most of the time (rather than working on pointers to the heap).
As far as I can tell both of those assertions are wrong. In terms of original creation of C++ garbage collection probably wasn't considered at all. That would be the reason for not having it. Another reason would have been because C didn't have it. Other than that it is like many other additional features in C++, it one wants it then one can add it. As Stroustrup says.... http://www.research.att.com/~bs/bs_faq.html#garbage-collection[^] Secondly exactly what source leads you to believe that "most" value entities in C++ live on the stack versus the heap? And more importantly what makes you think that is the case for objects versus primitive types? (I don't really consider the consideration of such things as for loop index variables as valid candidates for this since no one is going to ever create those on the heap anyways.)
jschell wrote:
Unfortunately, this trade-off is still (and will be for years to come) absolutely unacceptable in many computing areas.
Presumably you mean as a absolute count rather than in comparison to all software fields.
What I mean is that there are many fields (although they are certainly a minority compared to all existing computing problems). Simply, there are sufficient areas to justify the existence of a language such as C++.
jschell wrote:
and the performance penalty (on modern compilers) equals zero.
You are claiming that data constructs in C++ have a zero cost? That is incorrect.
That's indeed what I am claiming and it is correct. I am not claiming that, for a specific, well-analyzed case, you can't build a better suited custom data structures (e.g. you could forego any resizing issues in a vector with a fixed-size buffer). I am, however, claiming that in a general case without any specific domain knowledge, C++ data structures have a zero performance overhead at runtime, compared to low-level Assembler implementations of the same problem. Of course, this is a theoretical upper bound. In practice, most compilers have difficulties attaining this level of optimization. But modern compilers come very close most of the time (so close, in fact, that the difference is not measurable on modern PCs). My point is, C++ provides a level of abstraction that is completely transparent and has no additional cost, compared to an equivalent solution without the use of abstraction.
jschell wrote:
In terms of original creation of C++ garbage collection probably wasn't considered at all. That would be the reason for not having it. Another reason would have been because C didn't have it.
First of all, I am pretty sure a GC was considered. Perhaps not in the first version of “C with classes” but later on. I am even pretty sure that I've read a statement saying this from one of the committee members but I can't find it now (I think it was even from Stroustrup himself, in TC++PL). Second, saying “because C didn't have it” is a real no-argument. C didn't have classes, yet we see them in C++. A GC could have been built to be completely unobtrusive and transparent on top of the memory management, thus providing backwards compatibility so this
-
What is the real difference, you ask? It is there in the title itself. Plus you may argue that c# is more typesafe and stuff; avoids any usually complex pointer logic; avoids pointers totally...yada yada yada... To me it is just the way c# language compiler was designed. When you come down to the compiler level you have to de-initialize an object and clear memory. No other way to do this. It may be a mammoth task in c++, but it is possible. Everything is possible. Those who say something is impossible are probably out of ideas (or lack of sample code maybe :confused:). Given indefinite time I believe developing applications in c++ would result in robust applications. However what most programmers do today is charge into the arena like a bull! I'd rather like to plan my path. And a piece of paper and a pen that writes is always a good start. I wonder who the hell said: time is money. I'd want to throw my pc at him, and say thankyou very much! It is what people are asking for. It is our society. Most of the time when customers ask developers to do something, they completely drop the ethical sense. The result of this is that you are being pressurized, unnecessarily; or worse the customers themselves pressurizing you, unnecessarily! For if it was the opposite case (i.e. the customers had this ethical knowledge) and they kept pressurizing you, there would at least be some sort of justice/sense in that! (You being nailed to the wall here is not the point). --deostroll
I seriously doubt this will happen. I listened to a presentation Dr. Stroustrup gave to a Canadian computer science club, and at the end he mentioned that the next standardization won't happen for another 1-2 years. It seems they are taking longer than anyone expected. I have been following the folks at Aonix, who have been marketing the idea of Java for real-time embedded applications. It seems their queer implementation of real-time Java depends on such things as using a C/C++ compiler and turning OFF the garbage collection feature to achieve the performance necessary for real-time computing. If you extrapolate the problems of using Java for something it was never intended for, i.e. real-time computing; you will realize garbage collection for C++ won't happen. I bet a new language will be created from scratch, and build upon some of the things Java and C++ do well. Kind regards,
David
-
jschell wrote:
Unfortunately, this trade-off is still (and will be for years to come) absolutely unacceptable in many computing areas.
Presumably you mean as a absolute count rather than in comparison to all software fields.
What I mean is that there are many fields (although they are certainly a minority compared to all existing computing problems). Simply, there are sufficient areas to justify the existence of a language such as C++.
jschell wrote:
and the performance penalty (on modern compilers) equals zero.
You are claiming that data constructs in C++ have a zero cost? That is incorrect.
That's indeed what I am claiming and it is correct. I am not claiming that, for a specific, well-analyzed case, you can't build a better suited custom data structures (e.g. you could forego any resizing issues in a vector with a fixed-size buffer). I am, however, claiming that in a general case without any specific domain knowledge, C++ data structures have a zero performance overhead at runtime, compared to low-level Assembler implementations of the same problem. Of course, this is a theoretical upper bound. In practice, most compilers have difficulties attaining this level of optimization. But modern compilers come very close most of the time (so close, in fact, that the difference is not measurable on modern PCs). My point is, C++ provides a level of abstraction that is completely transparent and has no additional cost, compared to an equivalent solution without the use of abstraction.
jschell wrote:
In terms of original creation of C++ garbage collection probably wasn't considered at all. That would be the reason for not having it. Another reason would have been because C didn't have it.
First of all, I am pretty sure a GC was considered. Perhaps not in the first version of “C with classes” but later on. I am even pretty sure that I've read a statement saying this from one of the committee members but I can't find it now (I think it was even from Stroustrup himself, in TC++PL). Second, saying “because C didn't have it” is a real no-argument. C didn't have classes, yet we see them in C++. A GC could have been built to be completely unobtrusive and transparent on top of the memory management, thus providing backwards compatibility so this
KLMR wrote:
That's indeed what I am claiming and it is correct. I am not claiming that, for a specific, well-analyzed case, you can't build a better suited custom data structures (e.g. you could forego any resizing issues in a vector with a fixed-size buffer).
Either you have a bottleneck on a data type construct or you do not. Either you see this all the time or you do not. If you do then a custom implementation based on the data that the application is using has a possibility of reducing the bottleneck impact. If you don't have a bottleneck then the point is moot.
KLMR wrote:
First of all, I am pretty sure a GC was considered. Perhaps not in the first version of “C with classes” but later on. I am even pretty sure that I've read a statement saying this from one of the committee members but I can't find it now (I think it was even from Stroustrup himself, in TC++PL). ... As for you quoting the Stroustrup C++ FAQ, I consider this funny because you obviously haven't read it yourself: In his answer regarding a GC, Stroustrup explicitly refers (and links) to a better way of managing memory in C++ (namely, employing RAII) [1].
You missed the point. I wasn't claiming that alternatives did not exist nor was I debating the merits of each. Your statement was absolute and not qualified in any way. It suggested that Stroustrup considered GC and dismissed it because your stated alternative was better. I was pointing out that was NOT the reason. Both alternatives exist now. Neither existed when C++ was first created (not for C++.) And in lieu of other evidence nothing I have seen suggests that your reason was why Stroustrup didn't add it. Now if you want to claim that it hasn't been added lately for that reason then I could see that. Although I suspect there are other reasons besides that.
KLMR wrote:
There's a fine (but important) distinction here. I didn't say most elements lived on the stack, I said most elements were treated as such.
Interesting point. I can only note that I am rather certain that you do not write a significant amount, nor probably even a measurable amount of the C++ code that exists in the world. So the fact that it can be done that way and perhaps even should, does mean that it is. I really haven't noticed that anyone was claiming that C++ code has escaped the problems of mis
-
KLMR wrote:
That's indeed what I am claiming and it is correct. I am not claiming that, for a specific, well-analyzed case, you can't build a better suited custom data structures (e.g. you could forego any resizing issues in a vector with a fixed-size buffer).
Either you have a bottleneck on a data type construct or you do not. Either you see this all the time or you do not. If you do then a custom implementation based on the data that the application is using has a possibility of reducing the bottleneck impact. If you don't have a bottleneck then the point is moot.
KLMR wrote:
First of all, I am pretty sure a GC was considered. Perhaps not in the first version of “C with classes” but later on. I am even pretty sure that I've read a statement saying this from one of the committee members but I can't find it now (I think it was even from Stroustrup himself, in TC++PL). ... As for you quoting the Stroustrup C++ FAQ, I consider this funny because you obviously haven't read it yourself: In his answer regarding a GC, Stroustrup explicitly refers (and links) to a better way of managing memory in C++ (namely, employing RAII) [1].
You missed the point. I wasn't claiming that alternatives did not exist nor was I debating the merits of each. Your statement was absolute and not qualified in any way. It suggested that Stroustrup considered GC and dismissed it because your stated alternative was better. I was pointing out that was NOT the reason. Both alternatives exist now. Neither existed when C++ was first created (not for C++.) And in lieu of other evidence nothing I have seen suggests that your reason was why Stroustrup didn't add it. Now if you want to claim that it hasn't been added lately for that reason then I could see that. Although I suspect there are other reasons besides that.
KLMR wrote:
There's a fine (but important) distinction here. I didn't say most elements lived on the stack, I said most elements were treated as such.
Interesting point. I can only note that I am rather certain that you do not write a significant amount, nor probably even a measurable amount of the C++ code that exists in the world. So the fact that it can be done that way and perhaps even should, does mean that it is. I really haven't noticed that anyone was claiming that C++ code has escaped the problems of mis
jschell wrote:
So re-phrasing, what makes you think that your opinion about the way in which objects should be used in C++ actually has anything to do with the way in which they are in fact commonly used?
Please let me be a bit arrogant in answering this question: I don't actually care what's commonly used. It's widely acknowledged that 80% of everything is crap (cf. Sturgeon's Law) and I firmly believe that it is counterproductive to waste time discussing crap. So, I don't care what's commonly done. I do care how it should be done. And Stroustup (and others) tell us how it should be done. Stroustrup himself said that, in his opinion, “C++ Is [his] favorite garbage collected language because it generates so little garbage.” The context in which he says this (as well as his reference to it in the FAQ) makes it obvious that this phrase alludes to RAII. => You might be right that most C++ code written uses pointers to objects and explicit memory management all over the place. However, it is widely acknowledged that this is bad C++ and I am not going to justify this assertion because others have done so time and again – I simply won't waste energy on an established, well-documented fact. There's certainly no single Right Way to program C++. But using explicit memory management excessively is certainly the wrong way.
-
jschell wrote:
So re-phrasing, what makes you think that your opinion about the way in which objects should be used in C++ actually has anything to do with the way in which they are in fact commonly used?
Please let me be a bit arrogant in answering this question: I don't actually care what's commonly used. It's widely acknowledged that 80% of everything is crap (cf. Sturgeon's Law) and I firmly believe that it is counterproductive to waste time discussing crap. So, I don't care what's commonly done. I do care how it should be done. And Stroustup (and others) tell us how it should be done. Stroustrup himself said that, in his opinion, “C++ Is [his] favorite garbage collected language because it generates so little garbage.” The context in which he says this (as well as his reference to it in the FAQ) makes it obvious that this phrase alludes to RAII. => You might be right that most C++ code written uses pointers to objects and explicit memory management all over the place. However, it is widely acknowledged that this is bad C++ and I am not going to justify this assertion because others have done so time and again – I simply won't waste energy on an established, well-documented fact. There's certainly no single Right Way to program C++. But using explicit memory management excessively is certainly the wrong way.
KLMR wrote:
But using explicit memory management excessively is certainly the wrong way.
I suspect that if one uses a custom GC for C++ and uses it consistently and correctly throughout one application then there would be no problem with memory either. And I know that if one uses explicit allocation correctly throughout an application then there is no problem with memory either. So in terms of correct usage I can't see how any of the alternatives are better. So it would seem relevant to me to discuss what happens when there are problems. Now your suggested technique which based on the examples that Stroustrup provides, requires a number of different sub-strategies. While I know that explicit management just employes one (clean it up if you create it.) And I expect that the custom GC methodologies provide only a few strategies as well. So I wouldn't be surprised if some other strategy, in a less perfect environment, might be comparable if not better.