Versioning
GLSL is a versioning and compatibility nightmare: There are, at the
time of writing, fourteen different versions of GLSL in use. The
versions of OpenGL and GLSL available are tied to hardware and to
OpenGL drivers. Different versions of GLSL differ wildly in syntax
and in the names of functions defined in the standard library. The
same program may have to be rewritten five or six times to deal
with trivial syntax differences between versions. The standard
recommendation is for programs to explicitly mark the version of
GLSL for which they're intended by including a
#version directive at the start
of the file. Without this directive, many GLSL implementations
fall back to using the oldest available version, which then typically
means that the compiler rejects the program as invalid. With a
#version directive included, the
programmer is asserting that he/she wishes to use a specific version
which, of course, may not be available. Certain versions of OpenGL
(such as OpenGL ES 2), place arbitrary restrictions on programs
(such as not being able to declare multiple fragment shader outputs).
Most programmers attempt to work around these problems by layering
on hacks and preprocessor macros. This is obviously unacceptable to
programmers that actually care about correctness.
Correctness
GLSL is a nightmare from the perspective of correctness: Programs
are parsed and type-checked at runtime. The commitee that mismanages
OpenGL decided that all OpenGL drivers should implement their own compilers.
Apart from the inevitable correctness issues that stem from this requirement,
this also means that errors that should be entirely statically detectable
are signalled at the latest possible stage (run time). Systems that use
thousands of GLSL shaders are required to do obscene amounts of
testing to ensure that all of their shaders are valid GLSL.
The language, on one hand, requires explicit type conversions. This is
generally beneficial because there are none of magical implicit type
conversions that appear in somewhat more weakly-typed languages. The
language then works hard to eliminate the beneficial aspects by overloading
all functions and operators, so that the programmer really has no idea
which particular overloaded variant is being used .
The language has no module system and simply dumps its entire standard
library into the same namespace as the programmer's code. The programmer
must explicitly prefix the names of any defined functions or variables
in order to avoid potential collisions. The OpenGL committee are free to
introduce new name collisions at any time.
There are also very limited facilities for inspecting programs that
have been compiled. For example, the GLSL compiler is free to remove
any program inputs or parameters that is has deemed to be unused (and
has therefore optimized out). The programmer using the shading program
wants to be able to assign values to inputs by name. Unfortunately,
without the programmer manually parsing the original program, there
is no way to tell the difference between an input or parameter that
has been optimized out, and an input or parameter that never existed
in the first place. There is no way to distinguish between "The compiler
removed the parameter" and "I got the name of the parameter wrong".
The GLSL compiler obviously has this information, but
it is not made available to the programmer. In order to really guarantee
correctness, it's necessary for the programmer to reimplement parts
of the GLSL compiler!