N3888 Discussion

275 views
Skip to first unread message

wolfei...@gmail.com

unread,
Jan 20, 2014, 6:31:02 PM1/20/14
to grap...@isocpp.org
I've recently viewed N3888. I've got a few issues with this that I'd like to raise.

First, we need to start with the motivation for this paper. The problem is that virtually all of the listed example use cases require massive amounts of functionality not provided. There's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability. Not to mention all of the truly vast support code that would be required to handle some of the proposed use cases, also not provided, some of which goes beyond merely support. For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support? The proposed functionality is a drop in the proverbial bucket, and a waste of the Committee's time.

Second, the design decisions presents little justification for choosing Cairo. The fact that it has been used in places like Firefox is essentially just an appeal to authority fallacy, where the authority is unnamed Firefox developers. There are undoubtedly innumerable projects that use Singletons all over the place, but they should not be Standardised. The Motivation page lists several available choices for developers, and basing an API on one of them isn't even considered.

It's stated that application of mechanical rules can convert the Cairo API into a C++ API. This makes the process sound simple and easy, when in reality, it's anything but. The mechanical rules are several pages of Standardese. Furthermore, the benefits of mechanical transformation aren't discussed. The effort in performing a manual translation would be comparatively minimal, and would produce results that would be of substantially higher quality.

When discussing the choice to use Cairo, the output of the mechanical translator is described as an object-orientated C++ API. This is an extremely charitable description at best. For simple example, the numerous POD structs which have no constructors. And matrix, which has no constructors but plenty of two-phase initialization methods, and no operator overloads. The error handling facilities are also extremely primitive. drawing_exception doesn't really contain any useful data. If I attempt to load a font and get "user_font_error", this is not going to enable me to solve the problem, because I have no useful data about that problem.

The context object is the very epitome of evil. Even OpenGL has been moving away from this stuff- they cut the matrix stack and are standardising DSA. Using it essentially involves keeping the current state imagined in my head whilst I manually push and pop off some stack hidden somewhere. I set all the state to some invisible variable somewhere, hope nobody else needed these essentially global variables, and then try to use it. What are the concurrency guarantees involved in these methods? How is my compiler going to optimize pushes and pops off a stack on the heap somewhere else, instead of on my function-local stack?

Using Cairo and then fixing all of these issues so that the API was of a sufficient quality to be Standardised would be equivalent to just starting from scratch. A much better start would be the latest generation of Microsoft APIs. Not every aspect of all of them is relevant, but as a group, they are generally capable and far better designed. For example, DirectWrite includes proper Unicode rendering support, and ID3D11Device/ID3D11DeviceContext design solves the issue of concurrency. The mathematical support libraries aren't perfection but they are at least basically competent.

Thirdly, the native handles issue is not as simple as it first appears. The issue of threading is vastly different to the issue of rendering. There are far fewer useful implementations of a threading API per platform. Virtually all threading implementations on Windows will offer a Win32 thread handle as a native handle, for example. This is not true of rendering, which could have several reasonable implementations. There are far fewer useful operations on threads themselves. And finally, the use of a thread does not often depend on other related objects. For example, if I have an implementation backed by DX11, and I have an ID3D11DeviceContext, this is useless to me without an ID3D11Device. Mutating that device context would be extremely risky. The implementation cannot just return a pointer for me to mutate at will- virtually every operation would destroy the rendering state on which it depends. The implementation needs to know when I am drawing, when I am done, what resources I used, and all of that before they are even created. Many usages require creation flags to support them, for example D3DUSAGE_DYNAMIC. In this case, the implementation would effectively need to know my intentions ahead of time. This information is not exposed through a simple native_handle() scheme.

Abstract platform groups is another matter, though. It's been fifteen years since Glide died, and no new serious contenders have risen. Whilst Mantle is in a unique position here, it's also well out of the target groups. Every platform that supports Mantle will also support DX or OGL. Mantle users are explicitly looking for a low-level, direct-to-GPU approach and are not going to be interested in the Committee's abstraction. And it will be years before it is obvious whether or not it's worth serious attention. However, more generally, the issue is less about the raw underlying API, but more about the underlying hardware. No matter what drawing API is used, it is impossible to port an application from Windows desktop to Windows Phone simply by rebuilding it. The entire user interface must be redesigned to provide a positive user experience.

Ultimately, what this really comes down to is a lack of focus on the motivation. If the motivation is to provide for programmers to produce simple interactive applications with C++, then the proposal need not concern itself with details like what APIs are used or even, to a fair extent, what the result should look like. It should focus on issues like creating windows, providing for Unicode input, processing, and output, providing for common controls, touch and mouse input, concurrency, and such issues. It's simple enough to provide something like the D3DControl that WPF has on top of that for user-provided drawing. This would be vastly more useful than solving the non-problem of having to use an external drawing API given an external drawing API, external Unicode support, external input, etc.

N3888 is fundamentally broken, both in motivation, and implementation.

Michael McLaughlin

unread,
Jan 20, 2014, 10:48:01 PM1/20/14
to grap...@isocpp.org
On Mon, Jan 20, 2014 at 6:31 PM, <wolfei...@gmail.com> wrote:
I've recently viewed N3888. I've got a few issues with this that I'd like to raise.

First, we need to start with the motivation for this paper. The problem is that virtually all of the listed example use cases require massive amounts of functionality not provided. There's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability. Not to mention all of the truly vast support code that would be required to handle some of the proposed use cases, also not provided, some of which goes beyond merely support. For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support? The proposed functionality is a drop in the proverbial bucket, and a waste of the Committee's time.

 
The listed example uses cases are these: "Application programmers write programs that often need to render or display basic 2D graphics, including for introductory examples. Some need to display images. Some need to create simple charts and graphs. Some need to display text beyond the capabilities offered by the C++ console. Many application types call for all three of these capabilities along with the ability to interact with them using keyboard, mouse, and (more and more) touch.". With the exception of the last sentence I'm afraid I don't see anything that "require[s] massive amounts of functionality not provided." And for the last sentence, the paper acknowledges that this functionality is missing a few paragraphs later: "The scope of this proposal is limited to 2D drawing. It is expected that there will be one or more additional proposals which will add additional features such as the ability to capture and process keyboard, mouse, and touch input.".
 
As for your statement that "[t]here's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability", I again must profess that I simply do not know what "bunch of platform-specific APIs" you think are needed. If you were to provide some specifics I would try to address them. That said, even conceding that point arguendo I disagree with it. I think that adding a standard 2D drawing API when applications which use it will also require non-standard code is beneficial. 2D drawing is a reasonably self-contained domain and one which is used on a great many platforms for a great many purposes. As such it is both relatively easy to standardize (because it is contained) and beneficial to standardize (because it is used so often). To me the question was "can it be standardized?" and the answer, after examining various cross-platform drawing APIs (e.g. cairo, Qt's QPainter, openFrameworks, and cinder) was yes.
 
"For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support?" The answer is that we did propose such an interface so the question of how we propose to do it is moot. The interface in question accepts UTF-8 strings. Implementations are required to render them to the same extent that Cairo's toy font API does. Implementers are encouraged to go beyond this and provide support for RTL, BiDi, proper kerning (e.g. for scripts such as Devanagari), etc. But we felt that even providing basic text rendering was a step in the right direction. If someone wishes to propose a more advanced API, I encourage them to do so as it would most certainly be useful.
 
The API as it stands now could be implemented using anything from bitmap fonts to something like DirectWrite. I consider this a good thing since it makes it possible for even hosted implementations to consider implementing this library if they need basic 2D drawing capabilities while staying within strict resource constraints. We never considered attempting to include a standardization of Unicode since it would be A) beyond the scope of SG 13; and B) likely to be contentious. While we are willing to spend time and see this process through, however long it takes, there is no reason to include something that is, at best, tangential that would almost assuredly take many years. In short, we saw no reason to sink our own ship by overloading it with someone else's cargo.
 
I'll let the Committee decide what is a waste of its time. Herb Sutter, the Convener of the ISO C++ Committee, is one of my co-authors, and in Chicago the Committee agreed to the creation of SG13. So I think they'll at least be willing to listen. (n.b. You may believe that by mentioning Herb and his roles that "an appeal to authority" is being made. I am merely stating facts: someone who has dedicated enough of his life to the standardization of C++ to be chosen for the role of Convener believes strongly enough in the value of this that he agreed to chair the SG and to be a co-author of this proposal. Maybe he is an outlier on this topic, but that's something we'll find out in Issaquah. Regardless, I believe in it and I'm proud to have Herb and Jason as my co-authors.)
 
If LWG/LEWG think it is a waste of time then they will dismiss it summarily and I will be sad since I have spent hundreds of hours on SG13 work at this point in time. But I and my co-authors think it has value and we have each staked various amounts of time on that belief. I am hopeful that the Committee will consider our proposal and provide valuable feedback and will know whether they will in a few short weeks.
 
Second, the design decisions presents little justification for choosing Cairo. The fact that it has been used in places like Firefox is essentially just an appeal to authority fallacy, where the authority is unnamed Firefox developers. There are undoubtedly innumerable projects that use Singletons all over the place, but they should not be Standardised. The Motivation page lists several available choices for developers, and basing an API on one of them isn't even considered.

 
 We chose cairo because "[it] provides cross-platform support for advanced 2D drawing... has demonstrated that it is implementable... [and] has a mature API which is... object-oriented in its design." There is a page and a half of more detailed reasoning. But the simple reason is that it met our goals. That does not mean that other libraries and APIs did not meet our goals. Simply that cairo did and so we chose it. I could have drafted a QPainter-based API but it would've been very difficult to separate 2D drawing from the other parts of Qt and we didn't want to try to standardize more than was required for basic 2D graphics rendering and display.
 
As for the claim that mentioning Firefox "is essentially just an appeal to authority fallacy", you have misapprehended our reasons for mentioning it. We mentioned that cairo is used by Firefox, Mono, and GTK+ because we wished to demonstrate to the Committee that well-known, cross-platform projects have successfully used cairo. It was stated as evidence of our claims about its cross-platform utility and advanced 2D drawing capabilities. We chose to mention projects that we expected Committee members to know. If you believe that the usage of cairo in these projects is trivial or that the maintainers of these projects are dissatisfied with their choice, by all means present your evidence. We did not discover any such evidence and in fact had various people we consider experts in this field praise cairo. If there are reasons not to use it we want to know them and we want the Committee to know them. So please do provide any negative evidence you may have, if any.
 
As for the analogy to singletons, they are a design pattern not a library and so the analogy does not really hold together in my view. Regardless, thread-safe function local static initialization (sometimes called "magic statics") are something that, among other things, makes using the singleton pattern practical in C++ and it was added to the Standard. Lastly, your argument about singletons could have been made about dynamically resizeable arrays, doubly-linked lists, and FIFO containers, yet vector, list, and stack are all part of the Standard Library.
 
 
It's stated that application of mechanical rules can convert the Cairo API into a C++ API. This makes the process sound simple and easy, when in reality, it's anything but. The mechanical rules are several pages of Standardese. Furthermore, the benefits of mechanical transformation aren't discussed. The effort in performing a manual translation would be comparatively minimal, and would produce results that would be of substantially higher quality.

 
We indeed do not have a design decisions section discussing the choice of mechanical transformation. I can't say that it ever occurred to me that one was needed. When something can be done by following a set of rules, then provided that the rules themselves are satisfactory, the results should prove consistent, thus eliminating the possibility of differing interpretations. That, by the way, is why the rules are several pages of Standardese. Precise language is required for such rules if consistency is to be achieved. Indeed the thing that concerns me the most is that there may be some ambiguity somewhere in the rules that I missed. If so I very much hope that folks from the Committee will identify any such problems so that they can be resolved.
 
As for a manual translation, I created such an API prior to the decision to use Cairo. I had a working implementation with much of the functionality. Then in Chicago Beman Dawes, a very wise person, suggested that we start from an existing, known API (he then wrote up a paper containing his suggestions; it is cited at the end of our proposal). At first I pressed on with my API since it was progressing nicely and I felt that it was clean and elegant. I still do, for that matter. But the wisdom of his words gradually penetrated my dense skull as I observed various debates about the relative merits of different approaches to various issues. At the Redmond meeting (notes cited at the end of the proposal), the last of my resistance to dropping my initial work and starting anew collapsed and Jason, Herb, and I explored options and decided on cairo.
 
When discussing the choice to use Cairo, the output of the mechanical translator is described as an object-orientated C++ API. This is an extremely charitable description at best. For simple example, the numerous POD structs which have no constructors. And matrix, which has no constructors but plenty of two-phase initialization methods, and no operator overloads. The error handling facilities are also extremely primitive. drawing_exception doesn't really contain any useful data. If I attempt to load a font and get "user_font_error", this is not going to enable me to solve the problem, because I have no useful data about that problem.

 
POD structs need no constructors and are even forbidden to have certain types of constructors (see: 9 [class]/1). We intentionally kept classes that could be PODs as PODs and we did not add in constructors where no cairo-equivalent existed for the type (excluding copy and move constructors for non-POD types since C does not have constructors per se). Examine a variety of graphics libraries and you will discover a number of POD types and enums. Again, we transformed what existed in cairo, but it should not be surprising that this is the case in cairo when it is also the case in, e.g., D3D, D2D, OpenGL, and Qt. We felt no need to dress up types to make them non-PODs and we strove to keep the transformation as simple as possible in this initial proposal so that we could elicit feedback from the Committee on what they felt would be beneficial changes to make.
 
We considered and rejected transforming Cairo's error API without getting feedback from the Committee first. There are a number of error types in cairo that can (and I believe should) be eliminated since they are user errors that should be handled with assertion failures. I believe that my co-authors felt the same way about that. But we also felt that we did not want to push the boundaries too much. We decided to see what the Committee thinks on that issue before we proceed with it. As for "user_font_error", it has no meaning at all currently since we did not include the user font API. But we might decide to and having an error that never occurs is no great loss. Since the semantics of all functions are as they are defined in the cairo API documentation, a review of that would show that the error status is question is not one you'd need to worry about. If the ultimate question is "why didn't we include the API documentation in the proposal" the answer is that there are legal questions which we sent to the appropriate people at ISO and we are still waiting for a response before we will know how properly to do that while complying both with cairo's IP license (MPL 1.1) and with ISO's IP licensing requirements.
 
The context object is the very epitome of evil. Even OpenGL has been moving away from this stuff- they cut the matrix stack and are standardising DSA. Using it essentially involves keeping the current state imagined in my head whilst I manually push and pop off some stack hidden somewhere. I set all the state to some invisible variable somewhere, hope nobody else needed these essentially global variables, and then try to use it. What are the concurrency guarantees involved in these methods? How is my compiler going to optimize pushes and pops off a stack on the heap somewhere else, instead of on my function-local stack?

 
One thing I intend to ask about (if I remember) is the Committee's opinion on moving state out of the context object and into separate objects. It would be a fairly massive change considering how cairo is designed though and its not something I consider critical. As for multithreading rendering, its A) an advanced topic beyond the scope of the proposal; and B) generally a bad idea. With OpenGL its done using multiple contexts (and would, presumably, be done the same way in cairo). With D3D11, it's done with deferred contexts which record command lists that are later played back on the immediate context. If you try to access the same context from multiple threads with D3D11, you get undefined behavior (i.e. if you're lucky it crashes). If you're trying to have reasonably smooth animations, you need to hit at least 30 FPS. That gives you at most 33.33333 ms per frame. Introducing any sort of avoidable blocking on your rendering thread is an invitation to disaster (by which I mean crummy looking animations due to terrible frame rates). There is no way to abstract away the realities of GPUs and frame rates. None I know of. I like the D3D11 approach, but I know others who think it's no different than OpenGL's display lists which never lived up to their expectations. The jury is still out on D3D11's approach, though.
 
 
Using Cairo and then fixing all of these issues so that the API was of a sufficient quality to be Standardised would be equivalent to just starting from scratch. A much better start would be the latest generation of Microsoft APIs. Not every aspect of all of them is relevant, but as a group, they are generally capable and far better designed. For example, DirectWrite includes proper Unicode rendering support, and ID3D11Device/ID3D11DeviceContext design solves the issue of concurrency. The mathematical support libraries aren't perfection but they are at least basically competent.

 
If Microsoft is willing to submit DirectWrite and D3D11 for standardization, I'm sure there would be interest among some people (and vehement opposition from others). But I'm not holding my breath waiting for that to happen. Instead I expect that Microsoft would implement this API using those technologies and the results on Microsoft platforms would be very good. You're also forgetting that the DirectX APIs you mentioned (with the exception of DirectXMath) are COM-based such that we'd need to import COM (or something like it) into the C++ Standard in order to make any of that happen. I may be willing to volunteer as Don Quixote now and again, but I'm no Captain Ahab. Someone else can chase that whale.
 

Thirdly, the native handles issue is not as simple as it first appears. The issue of threading is vastly different to the issue of rendering. There are far fewer useful implementations of a threading API per platform. Virtually all threading implementations on Windows will offer a Win32 thread handle as a native handle, for example. This is not true of rendering, which could have several reasonable implementations. There are far fewer useful operations on threads themselves. And finally, the use of a thread does not often depend on other related objects. For example, if I have an implementation backed by DX11, and I have an ID3D11DeviceContext, this is useless to me without an ID3D11Device. Mutating that device context would be extremely risky. The implementation cannot just return a pointer for me to mutate at will- virtually every operation would destroy the rendering state on which it depends. The implementation needs to know when I am drawing, when I am done, what resources I used, and all of that before they are even created. Many usages require creation flags to support them, for example D3DUSAGE_DYNAMIC. In this case, the implementation would effectively need to know my intentions ahead of time. This information is not exposed through a simple native_handle() scheme.

 
You seem to have missed the suggestion that the native handle could be, e.g., an implementation-defined struct. In this case it would be one that contained both an ID3D11DeviceContext and its corresponding ID3D11Device. Incidentally, since ID3D11DeviceContext inherits from ID3D11DeviceChild, you can just call ID3D11DeviceChild::GetDevice. But I thought that making it clear that a native handle didn't have to be a pointer to some existing native type if the circumstances warranted something else.
 

Abstract platform groups is another matter, though. It's been fifteen years since Glide died, and no new serious contenders have risen. Whilst Mantle is in a unique position here, it's also well out of the target groups. Every platform that supports Mantle will also support DX or OGL. Mantle users are explicitly looking for a low-level, direct-to-GPU approach and are not going to be interested in the Committee's abstraction. And it will be years before it is obvious whether or not it's worth serious attention. However, more generally, the issue is less about the raw underlying API, but more about the underlying hardware. No matter what drawing API is used, it is impossible to port an application from Windows desktop to Windows Phone simply by rebuilding it. The entire user interface must be redesigned to provide a positive user experience.

 
If it's an app that provides its own UI (such as many games do), then porting from Windows desktop to Windows Phone (or to any other platform) is a perfect example of a good use case for this API. There would still need to be some platform-specific logic, but much less than there would be without this. And even apps that do use the GUI widgets of a platform could still use this API for other 2D drawing. This is not a panacea and we know that. We didn't set out to make one. We set out to propose a standardized solution to a particular problem domain (2D drawing).
 

Ultimately, what this really comes down to is a lack of focus on the motivation. If the motivation is to provide for programmers to produce simple interactive applications with C++, then the proposal need not concern itself with details like what APIs are used or even, to a fair extent, what the result should look like. It should focus on issues like creating windows, providing for Unicode input, processing, and output, providing for common controls, touch and mouse input, concurrency, and such issues. It's simple enough to provide something like the D3DControl that WPF has on top of that for user-provided drawing. This would be vastly more useful than solving the non-problem of having to use an external drawing API given an external drawing API, external Unicode support, external input, etc.

N3888 is fundamentally broken, both in motivation, and implementation.

 
You apparently have a different idea in mind than what we did. With this proposal, we set out to provide a standardized 2D drawing API. I think we met that objective. (If I didn't we wouldn't have published the proposal yet). We did not set out to provide windowing, input, Unicode, common controls, etc., so it is no surprise to me that our proposal does not address those things. I hope you will take another look at our proposal in light of my responses to your concerns. Perhaps you will see it in a new light.
 
-Mike
 

--
You received this message because you are subscribed to the Google Groups "Graphics" group.
To unsubscribe from this group and stop receiving emails from it, send an email to graphics+u...@isocpp.org.
To post to this group, send email to grap...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/graphics/.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/graphics/59bf464f-1b98-4108-bed1-c714e20a61f6%40isocpp.org.

sthe...@gmail.com

unread,
Jan 21, 2014, 11:38:33 AM1/21/14
to grap...@isocpp.org, wolfei...@gmail.com
I just want to add one data point to this discussion: We at think-cell.com are trying to make our code base less Windows-centric and (independently) decided to move our 2D drawing to Cairo. So this is definitely a step in the right direction for us. 

--
Sebastian Theophil / Senior Software Engineer / think-cell.com 

wolfei...@gmail.com

unread,
Jan 26, 2014, 9:44:10 PM1/26/14
to grap...@isocpp.org
I've recently viewed N3888. I've got a few issues with this that I'd like to raise.

First, we need to start with the motivation for this paper. The problem is that virtually all of the listed example use cases require massive amounts of functionality not provided. There's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability. Not to mention all of the truly vast support code that would be required to handle some of the proposed use cases, also not provided, some of which goes beyond merely support. For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support? The proposed functionality is a drop in the proverbial bucket, and a waste of the Committee's time.

 
The listed example uses cases are these: "Application programmers write programs that often need to render or display basic 2D graphics, including for introductory examples. Some need to display images. Some need to create simple charts and graphs. Some need to display text beyond the capabilities offered by the C++ console. Many application types call for all three of these capabilities along with the ability to interact with them using keyboard, mouse, and (more and more) touch.". With the exception of the last sentence I'm afraid I don't see anything that "require[s] massive amounts of functionality not provided." And for the last sentence, the paper acknowledges that this functionality is missing a few paragraphs later: "The scope of this proposal is limited to 2D drawing. It is expected that there will be one or more additional proposals which will add additional features such as the ability to capture and process keyboard, mouse, and touch input.".

The first issue here is "Many". As far as I can see, you might as well say "Virtually all". I can hardly think of any useful utilities that draw images that don't do so interactively. I mean, correct me if I'm wrong here, but the Motivation section strongly implies "We'd like these cases to be written virtually or entirely in Standard-compliant code rather than external APIs".

The second issue here is interoperation. I'm not going to go around using QString, QButton, QWindow, and then std::drawing. It would be immeasurably simpler to use Qt for all these needs. For example, what if QButton is painted with OGL and std::drawing is implemented with DirectX? It would be vastly more reliable for me to stick to Qt for everything. There are similar decisions for deciding to use Microsoft APIs (especially in light of airspace issues that they love to throw in). Providing only one of these components means that I have no guarantee that it will work with any of the others, plus I'm still hard-coupled to whoever is providing them, like Windows or Qt. Even if it turns out that Qt uses OGL and my implementation of std::drawing uses OGL, using std::drawing isn't improving my situation at all- it's made it even worse, since I'm now dependent on an implementation detail and my code could never function on some other implementation that uses DirectX or GDI or something.

As for your statement that "[t]here's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability", I again must profess that I simply do not know what "bunch of platform-specific APIs" you think are needed. If you were to provide some specifics I would try to address them. That said, even conceding that point arguendo I disagree with it. I think that adding a standard 2D drawing API when applications which use it will also require non-standard code is beneficial. 2D drawing is a reasonably self-contained domain and one which is used on a great many platforms for a great many purposes. As such it is both relatively easy to standardize (because it is contained) and beneficial to standardize (because it is used so often). To me the question was "can it be standardized?" and the answer, after examining various cross-platform drawing APIs (e.g. cairo, Qt's QPainter, openFrameworks, and cinder) was yes.
 
Many things can be Standardized. We could introduce std::singleton<T>. We could introduce a std::matrix which, when constructed, sometimes wipes the user's hard drive and sometimes acts like a 4x4 matrix of floats. We can Standardise a component that facilitates for the introduction of a keylogger. But none of these things should be Standardised.

2D drawing is self-contained, except that you have to draw everything with the same drawing API, including if I want to interoperate with some 3D drawing somewhere, so if I ever intend to draw anything (e.g. user interface) then I need to know they're compatible. And if you want to draw Unicode text then you have to implement Unicode processing facilities, for example, line breaking Unicode text. And separating text into grapheme clusters so you can find the grapheme from the font. Which includes normalization. And it also involves validating the Unicode so that you don't try to end up rendering something illegal. So basically, it would be impossible to implement rendering Unicode text without implementing lots of Unicode algorithms. So you'd require implementers to implement it; but not provide it for users to use.

So it's completely not self contained at all. You'd require implementations to implement quite a lot of functionality in other areas, plus the implementation details are serious user-facing issues. This doesn't sound good at all.

"For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support?" The answer is that we did propose such an interface so the question of how we propose to do it is moot. The interface in question accepts UTF-8 strings. Implementations are required to render them to the same extent that Cairo's toy font API does. Implementers are encouraged to go beyond this and provide support for RTL, BiDi, proper kerning (e.g. for scripts such as Devanagari), etc. But we felt that even providing basic text rendering was a step in the right direction. If someone wishes to propose a more advanced API, I encourage them to do so as it would most certainly be useful.
 
The API as it stands now could be implemented using anything from bitmap fonts to something like DirectWrite. I consider this a good thing since it makes it possible for even hosted implementations to consider implementing this library if they need basic 2D drawing capabilities while staying within strict resource constraints. We never considered attempting to include a standardization of Unicode since it would be A) beyond the scope of SG 13; and B) likely to be contentious. While we are willing to spend time and see this process through, however long it takes, there is no reason to include something that is, at best, tangential that would almost assuredly take many years. In short, we saw no reason to sink our own ship by overloading it with someone else's cargo.

I've already described how you essentially already are anyway. But what I think is more important is that if you actually address those issues, you would end up with something that I feel would address more useful use cases. Pretty much the only thing you can do right now is blindly render to a file or something- pretty much all the user-facing use cases are out the window due to airspacing and other complications.

 
Second, the design decisions presents little justification for choosing Cairo. The fact that it has been used in places like Firefox is essentially just an appeal to authority fallacy, where the authority is unnamed Firefox developers. There are undoubtedly innumerable projects that use Singletons all over the place, but they should not be Standardised. The Motivation page lists several available choices for developers, and basing an API on one of them isn't even considered.

 
 We chose cairo because "[it] provides cross-platform support for advanced 2D drawing... has demonstrated that it is implementable... [and] has a mature API which is... object-oriented in its design." There is a page and a half of more detailed reasoning. But the simple reason is that it met our goals. That does not mean that other libraries and APIs did not meet our goals. Simply that cairo did and so we chose it. I could have drafted a QPainter-based API but it would've been very difficult to separate 2D drawing from the other parts of Qt and we didn't want to try to standardize more than was required for basic 2D graphics rendering and display.

Anyone reading the proposed API can clearly determine that it is neither mature, nor object orientated. It would be difficult to find a better definition of what is not those things. There are many drawing APIs which are implemented and support drawing, many of which are a bit (not necessarily always a lot) closer to mature object-orientated approaches. (Also, it's hard to display images without for example windows, and displaying them doesn't have a huge quantity of meaning without user input).
 
As for the claim that mentioning Firefox "is essentially just an appeal to authority fallacy", you have misapprehended our reasons for mentioning it. We mentioned that cairo is used by Firefox, Mono, and GTK+ because we wished to demonstrate to the Committee that well-known, cross-platform projects have successfully used cairo. It was stated as evidence of our claims about its cross-platform utility and advanced 2D drawing capabilities. We chose to mention projects that we expected Committee members to know. If you believe that the usage of cairo in these projects is trivial or that the maintainers of these projects are dissatisfied with their choice, by all means present your evidence. We did not discover any such evidence and in fact had various people we consider experts in this field praise cairo. If there are reasons not to use it we want to know them and we want the Committee to know them. So please do provide any negative evidence you may have, if any.

It's not my job to suggest that the maintainers of Firefox are unhappy with Cairo. It's your job to show that they are happy with Cairo. Even if they are, that's a very long way away from suitable for Standardisation. For a simple example, Google's style guide forbids exceptions, and no doubt they're quite happy with exception-less libraries for this reason, but that would be a fairly major negative in weighting an API for Standardisation, not a positive. How did Firefox solve the issue of different implementations and airspacing, for example? How does Firefox handle concurrency with Cairo? How do they handle interoperation with their other technologies? Did they have to duplicate a bunch of Unicode functionality? Stating that Firefox uses Cairo, which is what is done in the proposal, is a very, very long way from meaningful support for the proposal.

If you've had experts in the field praise Cairo, then show it. Tell me how many you asked; who they were; and exactly how each of them responded (Also, try not to confuse "Implemented new anti-aliasing algorithm" with "Designed Standard-quality APIs", since they're entirely different fields).
 
As for the analogy to singletons, they are a design pattern not a library and so the analogy does not really hold together in my view. Regardless, thread-safe function local static initialization (sometimes called "magic statics") are something that, among other things, makes using the singleton pattern practical in C++ and it was added to the Standard. Lastly, your argument about singletons could have been made about dynamically resizeable arrays, doubly-linked lists, and FIFO containers, yet vector, list, and stack are all part of the Standard Library.

It absolutely could, and it absolutely should. Those things should not have been Standardised just because they could be or just because people use them. They should have been Standardised because virtually all users of the language need them, and because implementing them yourself in a safe and performant manner is actually extremely difficult (still finding exception safety bugs in MSVC2013's vector and poor performance with their deque). Also because most hand-rolled containers, as far as I'm aware, had an abysmal design and the STL was actually a big improvement over them. Also because they are common vocabulary types between libraries. On the other hand, just "Use Cairo directly if you like Cairo" is not especially difficult and carries many advantages over Standardising Cairo. Such as, "Since my 3D content is rendered with DX11, I will use D2D and DWrite instead of Cairo to guarantee correct interoperability". Or "Since I am using Qt for basically everything else, I will use QPainter".

It's stated that application of mechanical rules can convert the Cairo API into a C++ API. This makes the process sound simple and easy, when in reality, it's anything but. The mechanical rules are several pages of Standardese. Furthermore, the benefits of mechanical transformation aren't discussed. The effort in performing a manual translation would be comparatively minimal, and would produce results that would be of substantially higher quality.
 
We indeed do not have a design decisions section discussing the choice of mechanical transformation. I can't say that it ever occurred to me that one was needed. When something can be done by following a set of rules, then provided that the rules themselves are satisfactory, the results should prove consistent, thus eliminating the possibility of differing interpretations. That, by the way, is why the rules are several pages of Standardese. Precise language is required for such rules if consistency is to be achieved. Indeed the thing that concerns me the most is that there may be some ambiguity somewhere in the rules that I missed. If so I very much hope that folks from the Committee will identify any such problems so that they can be resolved.
 
As for a manual translation, I created such an API prior to the decision to use Cairo. I had a working implementation with much of the functionality. Then in Chicago Beman Dawes, a very wise person, suggested that we start from an existing, known API (he then wrote up a paper containing his suggestions; it is cited at the end of our proposal). At first I pressed on with my API since it was progressing nicely and I felt that it was clean and elegant. I still do, for that matter. But the wisdom of his words gradually penetrated my dense skull as I observed various debates about the relative merits of different approaches to various issues. At the Redmond meeting (notes cited at the end of the proposal), the last of my resistance to dropping my initial work and starting anew collapsed and Jason, Herb, and I explored options and decided on cairo.

I read N3825. It doesn't discuss why this approach was taken at all. It just says "We chose Cairo, then we created some mechanical rules". The main issues that I'm seeing here with the mechanical approach are firstly, it seems to me that you've practically put more effort into the mechanical rules already than would be necessary to simply derive a C++ API from Cairo manually, and secondly, the output is still embarrassingly low quality and would need substantial work before being suitable for Standardisation (even ignoring all the other issues I've raised).

I'll be back with more tomorrow.

Michael McLaughlin

unread,
Jan 27, 2014, 3:13:19 AM1/27/14
to grap...@isocpp.org
On Sun, Jan 26, 2014 at 9:44 PM, <wolfei...@gmail.com> wrote:
I've recently viewed N3888. I've got a few issues with this that I'd like to raise.

First, we need to start with the motivation for this paper. The problem is that virtually all of the listed example use cases require massive amounts of functionality not provided. There's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability. Not to mention all of the truly vast support code that would be required to handle some of the proposed use cases, also not provided, some of which goes beyond merely support. For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support? The proposed functionality is a drop in the proverbial bucket, and a waste of the Committee's time.

 
The listed example uses cases are these: "Application programmers write programs that often need to render or display basic 2D graphics, including for introductory examples. Some need to display images. Some need to create simple charts and graphs. Some need to display text beyond the capabilities offered by the C++ console. Many application types call for all three of these capabilities along with the ability to interact with them using keyboard, mouse, and (more and more) touch.". With the exception of the last sentence I'm afraid I don't see anything that "require[s] massive amounts of functionality not provided." And for the last sentence, the paper acknowledges that this functionality is missing a few paragraphs later: "The scope of this proposal is limited to 2D drawing. It is expected that there will be one or more additional proposals which will add additional features such as the ability to capture and process keyboard, mouse, and touch input.".

The first issue here is "Many". As far as I can see, you might as well say "Virtually all". I can hardly think of any useful utilities that draw images that don't do so interactively. I mean, correct me if I'm wrong here, but the Motivation section strongly implies "We'd like these cases to be written virtually or entirely in Standard-compliant code rather than external APIs".

The second issue here is interoperation. I'm not going to go around using QString, QButton, QWindow, and then std::drawing. It would be immeasurably simpler to use Qt for all these needs. For example, what if QButton is painted with OGL and std::drawing is implemented with DirectX? It would be vastly more reliable for me to stick to Qt for everything. There are similar decisions for deciding to use Microsoft APIs (especially in light of airspace issues that they love to throw in). Providing only one of these components means that I have no guarantee that it will work with any of the others, plus I'm still hard-coupled to whoever is providing them, like Windows or Qt. Even if it turns out that Qt uses OGL and my implementation of std::drawing uses OGL, using std::drawing isn't improving my situation at all- it's made it even worse, since I'm now dependent on an implementation detail and my code could never function on some other implementation that uses DirectX or GDI or something.

 
Again, I quote from the paper: "The scope of this proposal is limited to 2D drawing. It is expected that there will be one or more additional proposals which will add additional features such as the ability to capture and process keyboard, mouse, and touch input." You seem to take issue with the fact that this paper is not proposing standardizing Qt. And then conclude that since it is not proposing standardizing Qt it is not useful for anything.
 
By design this will be a lightweight 2D drawing library. See http://isocpp.org/files/papers/n3791.html . N3888 is a proposal intended to move the process along. It proposes a starting point. It does not propose the final destination. Indeed N3888 itself may not be the starting point. If that's the result, that's ok with me so long as it serves as the catalyst that generates a starting point.
 
I would like to address your concerns, but your concerns seem to be that the scope of this proposal is too limited. The only response I have to give is to refer you to N3791. Beman Dawes makes many excellent points in that paper, among them is that too large a scope is a recipe for failure. The goal here is 2D drawing. It is not to be Qt or GTK+ or DirectX or OpenGL or Windows or X11 or anything else of significantly larger scope. I do appreciate that the ability to using the library with other technologies will help drive its adoption. But to standardize interoperation with a QWindow requires standardizing a QWindow. That's not our goal. We are seeking, ultimately, to standardize 2D drawing, and more precisely still an interface for 2D drawing operations (not any particular implementation). It's entirely possible that if this project is successful that the developers of Qt and other such libraries would be able to drop a lot of platform-specific code that they have and replace it with this.
 
Like with any standardized library, it is only the interface that is standardized, not the implementation. It is up to the implementors to provide good, useful implementations that meet the needs of their user base. You seem to be criticizing the fact that it is possible for implementors to deliver bad implementations and then to use that criticism as an argument against the very idea of standardizing 2D drawing. The argument is specious in that it is an equally valid argument against standardizing any interface and yet standardizing interfaces is a significant part of the Committee's work. The presence or absence of interoperability with Qt, OpenGL, DirectX, or any other technology is a design decision for the implementors. And rightly so since technologies change and are even replaced as computing evolves. But the concepts of vector drawing have not changed much, if at all, in decades. N3888 presents a proposed starting point in standardizing 2D drawing, one which leans towards vector drawing while also providing for rasterization of bitmap images. If the concepts that are desirable for this lightweight API are present, then SG13 can turn towards the goal of turning the initial work in N3888 into a clean, modern C++ library that will eventually be ready to be proposed as a TS and perhaps one day for inclusion in the Standard itself.
 
 

As for your statement that "[t]here's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability", I again must profess that I simply do not know what "bunch of platform-specific APIs" you think are needed. If you were to provide some specifics I would try to address them. That said, even conceding that point arguendo I disagree with it. I think that adding a standard 2D drawing API when applications which use it will also require non-standard code is beneficial. 2D drawing is a reasonably self-contained domain and one which is used on a great many platforms for a great many purposes. As such it is both relatively easy to standardize (because it is contained) and beneficial to standardize (because it is used so often). To me the question was "can it be standardized?" and the answer, after examining various cross-platform drawing APIs (e.g. cairo, Qt's QPainter, openFrameworks, and cinder) was yes.
 
Many things can be Standardized. We could introduce std::singleton<T>. We could introduce a std::matrix which, when constructed, sometimes wipes the user's hard drive and sometimes acts like a 4x4 matrix of floats. We can Standardise a component that facilitates for the introduction of a keylogger. But none of these things should be Standardised.

2D drawing is self-contained, except that you have to draw everything with the same drawing API, including if I want to interoperate with some 3D drawing somewhere, so if I ever intend to draw anything (e.g. user interface) then I need to know they're compatible. And if you want to draw Unicode text then you have to implement Unicode processing facilities, for example, line breaking Unicode text. And separating text into grapheme clusters so you can find the grapheme from the font. Which includes normalization. And it also involves validating the Unicode so that you don't try to end up rendering something illegal. So basically, it would be impossible to implement rendering Unicode text without implementing lots of Unicode algorithms. So you'd require implementers to implement it; but not provide it for users to use.

So it's completely not self contained at all. You'd require implementations to implement quite a lot of functionality in other areas, plus the implementation details are serious user-facing issues. This doesn't sound good at all.
 
I'm sorry that you seem to believe that SG13 must standardize Unicode text processing in order to provide a lightweight 2D drawing API. As stated in the quoted text below, implementers would be required to render UTF-8 strings to the same extent that cairo's toy font API requires. I feel that this is a reasonable tradeoff between providing no text rendering capabilities and attempting to standardize something like DirectWrite or FreeType 2 + fontconfig. That you disagree is clear. The both of us rephrasing the same arguments is unlikely to change either my opinion or your opinion. Ultimately the SG needs to decide whether to opt for: no text rendering, some minimum level of text rendering (with an API that leaves implementers open to provide more than is required), or full Unicode processing + the best text rendering that can be had. I again defer to N3791 as it states the reasons I believe the last option to be untenable very concisely and was written by someone whose experience in the standardization process is far more extensive than my own.
 


"For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support?" The answer is that we did propose such an interface so the question of how we propose to do it is moot. The interface in question accepts UTF-8 strings. Implementations are required to render them to the same extent that Cairo's toy font API does. Implementers are encouraged to go beyond this and provide support for RTL, BiDi, proper kerning (e.g. for scripts such as Devanagari), etc. But we felt that even providing basic text rendering was a step in the right direction. If someone wishes to propose a more advanced API, I encourage them to do so as it would most certainly be useful.
 
The API as it stands now could be implemented using anything from bitmap fonts to something like DirectWrite. I consider this a good thing since it makes it possible for even hosted implementations to consider implementing this library if they need basic 2D drawing capabilities while staying within strict resource constraints. We never considered attempting to include a standardization of Unicode since it would be A) beyond the scope of SG 13; and B) likely to be contentious. While we are willing to spend time and see this process through, however long it takes, there is no reason to include something that is, at best, tangential that would almost assuredly take many years. In short, we saw no reason to sink our own ship by overloading it with someone else's cargo.

I've already described how you essentially already are anyway. But what I think is more important is that if you actually address those issues, you would end up with something that I feel would address more useful use cases. Pretty much the only thing you can do right now is blindly render to a file or something- pretty much all the user-facing use cases are out the window due to airspacing and other complications.

 
You quite clearly seem to think that C++ needs to standardize Unicode processing. I do not have the time or requisite knowledge to craft such a proposal. I am focused on the work of SG13 (though I am also trying to keep up with the discussions of some other proposals that I find interesting). Though I am still pretty new to the standardization process, I have already learned the truth of the statement that "nothing happens without a proposal." As I said above, I don't think we need to standardize this to provide a minimum level of text rendering. Yes, implementers would need to deal with some UTF-8 processing. That does not necessitate standardizing it. It may be a good idea to standardize it and if so I hope that you or someone else will write a proposal to do so. But seeing as every major web browser already deals with UTF-8 processing, the functionality already exists. To the extent that your complaint is that it would be a burden on implementers, I present IE, Chrome, Firefox, Opera, and Safari as exhibits A through E that any such burden would be minimal (apologies to the authors of any browsers I inadvertently neglected to include). To the extent that your complaint is that you think time would better be spent standardizing Unicode processing, I again invite you to create and submit a proposal.
 
You can already do more with this proposal than "blindly render to a file or something" and this is just a proposal to set a starting point. The reference implementation (announced in a different post to this group) demonstrates rendering to a Win32 window. There is already a fork of it that demonstrates rendering to an X11 window on a GNU/Linux system using GTK+. Unless you meant these to fit in the "or something" category, your assertion collapses in the face of evidence controverting it.
 
Sure, with some technologies airspace issues exist. Implementers will need to take that into account. It is possible (though highly doubtful) that some will fail to do so. If they fail to do so then they may inadvertently produce low quality implementations assuming they ship their product without creating any sort of test suite to verify its behavior. These hypothetical low quality implementations would only have minimal use to those who adopt them. It seems to be your argument that because of this we should abandon all notions of standardizing 2D drawing. I have already claimed and I claim again that this argument that implementations might be poor therefore why bother is specious.
 

 
Second, the design decisions presents little justification for choosing Cairo. The fact that it has been used in places like Firefox is essentially just an appeal to authority fallacy, where the authority is unnamed Firefox developers. There are undoubtedly innumerable projects that use Singletons all over the place, but they should not be Standardised. The Motivation page lists several available choices for developers, and basing an API on one of them isn't even considered.

 
 We chose cairo because "[it] provides cross-platform support for advanced 2D drawing... has demonstrated that it is implementable... [and] has a mature API which is... object-oriented in its design." There is a page and a half of more detailed reasoning. But the simple reason is that it met our goals. That does not mean that other libraries and APIs did not meet our goals. Simply that cairo did and so we chose it. I could have drafted a QPainter-based API but it would've been very difficult to separate 2D drawing from the other parts of Qt and we didn't want to try to standardize more than was required for basic 2D graphics rendering and display.

Anyone reading the proposed API can clearly determine that it is neither mature, nor object orientated. It would be difficult to find a better definition of what is not those things. There are many drawing APIs which are implemented and support drawing, many of which are a bit (not necessarily always a lot) closer to mature object-orientated approaches. (Also, it's hard to display images without for example windows, and displaying them doesn't have a huge quantity of meaning without user input).
 
Cairo is mature. Cairo is (for a C API) object oriented in its design. The proposal is a first draft aimed at establishing a starting point. It is not a final work and is intentionally simple. My desire is that the final product of SG13 will be a clean, modern C++ 2D drawing API that will be adopted as a TS and eventually incorporated into the Standard. If N3888 were incorporated into the Standard as-is, I would feel compelled to request that the Issaquah Police Department investigate the possibility that we had all been unknowingly exposed to some substance with psychotropic properties.
 
I stated that user input will come in a later proposal in my previous response. In fact you quoted the part of my response where I addressed that. I do not know why you ignored it, despite quoting it, in order that you might say "displaying [images] doesn't have a huge quantity of meaning without user input" with the implication that user input is not, in fact, something that is being contemplated whereas it states both in the proposal and in the post you quoted from that user input is being contemplated.
 

 
As for the claim that mentioning Firefox "is essentially just an appeal to authority fallacy", you have misapprehended our reasons for mentioning it. We mentioned that cairo is used by Firefox, Mono, and GTK+ because we wished to demonstrate to the Committee that well-known, cross-platform projects have successfully used cairo. It was stated as evidence of our claims about its cross-platform utility and advanced 2D drawing capabilities. We chose to mention projects that we expected Committee members to know. If you believe that the usage of cairo in these projects is trivial or that the maintainers of these projects are dissatisfied with their choice, by all means present your evidence. We did not discover any such evidence and in fact had various people we consider experts in this field praise cairo. If there are reasons not to use it we want to know them and we want the Committee to know them. So please do provide any negative evidence you may have, if any.

It's not my job to suggest that the maintainers of Firefox are unhappy with Cairo. It's your job to show that they are happy with Cairo. Even if they are, that's a very long way away from suitable for Standardisation. For a simple example, Google's style guide forbids exceptions, and no doubt they're quite happy with exception-less libraries for this reason, but that would be a fairly major negative in weighting an API for Standardisation, not a positive. How did Firefox solve the issue of different implementations and airspacing, for example? How does Firefox handle concurrency with Cairo? How do they handle interoperation with their other technologies? Did they have to duplicate a bunch of Unicode functionality? Stating that Firefox uses Cairo, which is what is done in the proposal, is a very, very long way from meaningful support for the proposal.

 
You suggested that the authors of the paper engaged in "an appeal to authority fallacy", which is a form of logical fallacy and a charge that I personally take very seriously. Despite the hurtful nature of your accusation, I chose to believe that you had innocently misapprehended the reason we mentioned FireFox et al. As such, I did my best to clarify why we mentioned them (because they are evidence that well-known, cross-platform projects have used cairo successfully, thus demonstrating that its provides sufficient functionality to meet the requirements of a 2D drawing library). I then stated that, "[i]f you believe that the usage of cairo in these projects is trivial or that the maintainers of these projects are dissatisfied with their choice, by all means present your evidence." My evidence that they are happy with it is that they chose it, used it, and produced admirable products. I in no way said that it was your "job" to suggest that anyone is unhappy with cairo. I was merely suggesting two possible ways of controverting the prima facie evidence of satisfaction (namely, usage of the library).
 
The remainder of what you have written once again demands evidence of how implementation details were resolved. The committee does not standardize implementations, it standardizes interfaces. The fact that cairo has been implemented on many platforms is prima facie evidence of its implementability and that is the point at which I consider my own role in vetting implementability complete. I am not a compiler developer. If a compiler developer were to say that something in N3888 has implementability problems, that would need to be addressed. I have not heard or seen any such statements to date.
 

If you've had experts in the field praise Cairo, then show it. Tell me how many you asked; who they were; and exactly how each of them responded (Also, try not to confuse "Implemented new anti-aliasing algorithm" with "Designed Standard-quality APIs", since they're entirely different fields).
 
 
I do my best to choose my words carefully and in this instance I chose "we" not "I" because this information was relayed to me by Herb Sutter in the SG13 meeting whose notes are documented in N3825. Since specific names were not recorded in the minutes and since the communications were not made directly to me, I do not feel that it is proper for me to disclose them. All that N3825 records is that "[cairo]... has been endorsed by several other library developers (from Cinder and OpenFrameworks)". If you need more information that this, you will need to ask Herb. I do not know if he will be able to provide you with the details you demand (the conversations may well have been "off the record" and it is entirely possible that the reason no names were recorded was because he might never have mentioned any). I have no reason to ask Herb for details because I know him to be an honest, trustworthy person. I take him at his word when he tells me that graphics library experts he has spoken to have praised cairo. You are welcome to ask him for further details if you feel you need to do so, though.
 

As for the analogy to singletons, they are a design pattern not a library and so the analogy does not really hold together in my view. Regardless, thread-safe function local static initialization (sometimes called "magic statics") are something that, among other things, makes using the singleton pattern practical in C++ and it was added to the Standard. Lastly, your argument about singletons could have been made about dynamically resizeable arrays, doubly-linked lists, and FIFO containers, yet vector, list, and stack are all part of the Standard Library.

It absolutely could, and it absolutely should. Those things should not have been Standardised just because they could be or just because people use them. They should have been Standardised because virtually all users of the language need them, and because implementing them yourself in a safe and performant manner is actually extremely difficult (still finding exception safety bugs in MSVC2013's vector and poor performance with their deque). Also because most hand-rolled containers, as far as I'm aware, had an abysmal design and the STL was actually a big improvement over them. Also because they are common vocabulary types between libraries. On the other hand, just "Use Cairo directly if you like Cairo" is not especially difficult and carries many advantages over Standardising Cairo. Such as, "Since my 3D content is rendered with DX11, I will use D2D and DWrite instead of Cairo to guarantee correct interoperability". Or "Since I am using Qt for basically everything else, I will use QPainter".
 
We aren't looking to standardize cairo. The goal is to standardize a 2D drawing API. The proposal recommends using a mechanical transformation of cairo's C API into C++ as a starting point. I would be stunned if the Visual C++ team did not create a D3D/D2D/DWrite-based implementation of any 2D Drawing TS that may someday be adopted. As such, your implementation detail argument about D3D interop is unconvincing to me. I also expect that if a 2D Drawing TS is adopted that the Qt maintainers would look very closely at replacing all of the platform-specific code that underlies QPainter with the 2D Drawing TS such that, to the extent someone using QPainter also wanted to use the 2D Drawing TS (even though they provide very similar functionality), it's highly probable in my opinion that they would be able to do so. You are free to disagree, but since we don't standardize implementations there's really nothing to discuss in my opinion.

It's stated that application of mechanical rules can convert the Cairo API into a C++ API. This makes the process sound simple and easy, when in reality, it's anything but. The mechanical rules are several pages of Standardese. Furthermore, the benefits of mechanical transformation aren't discussed. The effort in performing a manual translation would be comparatively minimal, and would produce results that would be of substantially higher quality.
 
We indeed do not have a design decisions section discussing the choice of mechanical transformation. I can't say that it ever occurred to me that one was needed. When something can be done by following a set of rules, then provided that the rules themselves are satisfactory, the results should prove consistent, thus eliminating the possibility of differing interpretations. That, by the way, is why the rules are several pages of Standardese. Precise language is required for such rules if consistency is to be achieved. Indeed the thing that concerns me the most is that there may be some ambiguity somewhere in the rules that I missed. If so I very much hope that folks from the Committee will identify any such problems so that they can be resolved.
 
As for a manual translation, I created such an API prior to the decision to use Cairo. I had a working implementation with much of the functionality. Then in Chicago Beman Dawes, a very wise person, suggested that we start from an existing, known API (he then wrote up a paper containing his suggestions; it is cited at the end of our proposal). At first I pressed on with my API since it was progressing nicely and I felt that it was clean and elegant. I still do, for that matter. But the wisdom of his words gradually penetrated my dense skull as I observed various debates about the relative merits of different approaches to various issues. At the Redmond meeting (notes cited at the end of the proposal), the last of my resistance to dropping my initial work and starting anew collapsed and Jason, Herb, and I explored options and decided on cairo.

I read N3825. It doesn't discuss why this approach was taken at all. It just says "We chose Cairo, then we created some mechanical rules". The main issues that I'm seeing here with the mechanical approach are firstly, it seems to me that you've practically put more effort into the mechanical rules already than would be necessary to simply derive a C++ API from Cairo manually, and secondly, the output is still embarrassingly low quality and would need substantial work before being suitable for Standardisation (even ignoring all the other issues I've raised).

 
I'm sorry but I think the statement that there is no discussion of why cairo was chosen is contradicted by the contents of N3825. In particular: "What about Cairo (or CairoMM)? It is closer to C++, and it seems to be the intersection between Cinder and OpenFrameworks. It is already very cross platform also, and has been endorsed by several other library developers (from Cinder and OpenFrameworks)." I recognize that that is not much, but since these are minutes and not a transcription provided by a stenographer, they are distilled. That is one reason why N3888 contains a section called "Leveraging the Cairo API" which totals 746 words. It explains why cairo was chosen in more detail than N3825 does.
 
Could we have chosen something else? Sure. Are there other options that would likely have worked out ok? Yes. We chose cairo because we (Herb, Jason and I) decided we were going to create a proposal. Having made that decision, we were entitled by the fact that we would be the ones putting hundreds of hours into this effort to make such choices. We chose cairo and wrote N3888 and created a reference implementation. We are now working on samples, on ideas for improving the proposal, and on a presentation for Issaquah, amongst other things. As I said above, N3888 is not a finished product. It may even need one or more revisions before it is acceptable as a starting point. Anyone is welcome to write his or her own proposal. I would rather see recommendations for improving N3888, but if someone presents a clearly superior proposal, I'll drop N3888 (or whatever revision of it I'm working on at that point) and take up the better product. My goal is to see C++ developers have a high-quality standardized 2D Drawing library available to them. I will follow whatever seems like the best course to get there.
 
-Mike
 

Beman Dawes

unread,
Jan 30, 2014, 11:41:44 AM1/30/14
to grap...@isocpp.org
On Mon, Jan 27, 2014 at 3:13 AM, Michael McLaughlin <mike...@gmail.com> wrote:

<snip> Lengthy and detailed replies to comments about N3888 </snip>

Thanks to Mike McLaughlin for his work on N3888, and for crafting such careful replies to comments received.

I'm looking forward to the February 10th Issaquah C++ meeting, and moving this proposal forward toward an eventual lightweight graphs TS. If someone can come up with a better proposal, fine, but Mike has set a high bar that will have to be bettered.

--Beman Dawes
Reply all
Reply to author
Forward
0 new messages