
Daan Leijen wrote:
[...] An attribute has both a type "a" and a thing that it belongs to "w". I wonder why the "thing it belongs to" is absent from your approach as it seems quite fundamental to me.
Of course there is a "thing it belongs to" for state variables in OpenGL, too: It's the current rendering context (= the big, fat OpenGL state machine), but it is implicit in all OpenGL calls. Handling the context is beyond OpenGL's scope and normally handled by a GUI toolkit, e.g. GLUT. You could do this e.g. under X11 with GLX calls like glXMakeContextCurrent, which associates a context with the current OS thread (Hello, FFI list! :-), but this is rather unusual. You normally have a single context per window, and that's it. Furthermore, switching an OpenGL context could be rather heavyweight, as it potentially involves a lot of "real world" state changes on your graphics card (reprogramming texture units, swapping of display lists, flushing rendering pipelines, etc.). So this implicitness was a rather intentional design choice when the OpenGL API was created and should not be re-introduced artificially afterwards.
It allows you for example to organise the attributes in type classes and re-use the same attribute name for different kind of things.
Hmmm, For the reason stated above, I don't think that there will be type classes in HOpenGL similar to the usual "has a label" stuff in GUI bindings.
[ some Haskell code for Attr, get, Prop, (=:), and set omitted ... ]
That's basically what Graphics.UI.GIO.Attributes does, or did I miss something?
Now, regarding openGL with state variables, you would make attributes that work on those, for example:
value :: Attr (IORef a) a value = Attr (getIORef) (setIORef)
So, even openGL will assign attributes to certain kind of things.
Nope, state variables in OpenGL have nothing to do with IORefs or something similar, they are entities from the current context (= state machine), and are not mirrored on the Haskell side. If they can be set, there is an OpenGL call to do that, and if they can be read, there is an OpenGL call retrieving that part of the state. If one or both of the calls are missing from the API, there is a very good reason for this. The "w" in GIO's API would always be "()" in HOpenGL, and should therefore be hidden from the latter API. Otherwise the types and calls would look rather strange, and people would start asking what this omnipresent "()" should mean. In types the "()" could be hidden by appropriate "type" definitions, in function calls the extra argument can be supplied by a wrapper function.
Furthermore, you can still make a read/write distinction by putting "get" and ":=" in classes as you do:
class Readable attr where get :: attr w a -> w -> IO a
class Writable attr where (=:) :: attr w a -> a -> Prop w
instance Readable Attr where ... instance Writable Attr where ...
You can't make a distinction with a single Attr type, you need different ones for readable, writeable and r/w attributes. It's crucial IMHO that you get a type error when you e.g. apply "get" to a write-only attribute.
But I am personally a bit hesitant to do this as it might give rise to rather complex error messages [...]
Better a complex error message at compile time than a simple one at runtime. :-) Seriously, I don't expect real problems if we stay within H98.
[...] Therefore, i am quite curious if the approach that is focused on "Attributes" as sketched in this mail will also work for openGL.
Despite my comments above, I think there is common ground: Doing some trivial impedance matching (nuking the "()") won't pose real problems in HOpenGL's case, so the question is: Can you fit the read/write distinction into GIO? BTW, I had a closer look at GLUT and OpenAL (something I really like to write a binding for, too) and found that the concepts in question would be rather beneficial for a Haskell API. OTOH, this should have been expected, because those APIs are closely modeled after OpenGL. Cheers, S.