Shader classes, mixins and inheritance
Stride Shading Language (SDSL) is an extension of HLSL, which makes it closer to C# syntax and concepts. The language is object-oriented:
- shader classes are the foundation of the code
 - shader classes contain methods and members
 - shader classes can be inherited, methods can be overridden
 - member types can be shader classes
 
SDSL uses an original way to handle multiple inheritance. Inheritance is performed through mixins, so the order of inheritance is crucial:
- the order of inheritance defines the actual implementation of a method (the last override)
 - if a mixin appears several times in the inheritance, only the first occurrence is taken into account (as well as its members and methods)
 - to can call the previous implementation of a method, use 
base.<method name>(<arguments>) 
Keywords
SDSL uses the keywords as HLSL, and adds new ones:
stage: method and member keyword. This keyword makes sure the method or member is only defined once and is the same in the compositions.stream: member keyword. The member is accessible at every stage of the shader. For more information, see Automatic shader stage input/out.streams: sort of global structure storing variables needed across several stages of the shader. For more information, see Automatic shader stage input/out.override: method keyword. If this keyword is missing, the compilation returns an error.abstract: used in front of a method declaration (without a body).clone: method keyword. When a method appears several times in the inheritance tree of a shader class, this keyword forces the creation of multiple instances of the method at each level of the inheritance instead of one. For more information, see Composition.Input: for geometry and tessellation shaders. For more information, see Shader stages.Output: for geometry and tessellation shaders. For more information, see Shader stages.Input2: for tessellation shaders. For more information, see Shader stages.Constants: for tessellation shaders. For more information, see Shader stages.
Abstract methods
Abstract methods are available in SDSL. They should be prefixed with the abstract keyword. You can inherit from a shader class with abstract methods without having to implement them; the compiler will simply produce a harmless warning. However, you should implement it in your final shader to prevent a compilation error.
Annotations
Like HLSL, annotations are available in SDSL. Some of the most useful ones are:
[Color]for float4 variables. The ParameterKey will have the typeColor4instead ofVector4. It also specifies to Game Studio that this variable should be treated as a color, so you can edit it in Game Studio.[Link(...)]specifies which ParameterKey to use to set this value. However, an independent default key is still created.[Map(...)]specifies which ParameterKey to use to set this value. No new ParameterKey is created.[RenameLink]prevents the creation of a ParameterKey. It should be used with[Link()].
Example code: annotations
shader BaseShader
{
    [Color] float4 myColor;
    [Link("ProjectKeys.MyTextureKey")]
    [RenameLink]
    Texture2D texture;
    [Map("Texturing.Texture0")] Texture2D defaultTexture;
};
Example code: inheritance
shader BaseInterface
{
    abstract float Compute();
};
shader BaseShader : BaseInterface
{
    float Compute()
    {
        return 1.0f;
    }
};
shader ShaderA : BaseShader
{
    override void Compute()
    {
        return 2.0f;
    }
};
shader ShaderB : BaseShader
{
    override void Compute()
    {
        float prevValue = base.Compute();
        return (5.0f + prevValue);
    }
};
Example code: the importance of inheritance order
Notice what happens when we change the inheritance order between ShaderA and ShaderB.
shader MixAB : ShaderA, ShaderB
{
};
shader MixBA : ShaderB, ShaderA
{
};
// Resulting code (representation)
shader MixAB : BaseInterface, BaseShader, ShaderA, ShaderB
{
    float Compute()
    {
        // code from BaseShader
        float v0 = 1.0f;
        // code from ShaderA
        float v1 = 2.0f;
        // code from ShaderB
        float prevValue = v1;
        float v2 = 5.0f + prevValue;
        return v2; // = 7.0f
    }
};
shader MixBA : BaseInterface, BaseShader, ShaderA, ShaderB
{
    float Compute()
    {
        // code from BaseShader
        float v0 = 1.0f;
        // code from ShaderB
        float prevValue = v0;
        float v1 = 5.0f + prevValue;
        // code from ShaderA
        float v2 = 2.0f;
        return v2; // = 2.0f
    }
};
Static calls
You can also use a variable or call a method from a shader without having to inherit from it. To do this, use <shader_name>.<variable or method_name>. It behaves the same way as a static call. 
Note that if you statically call a method that uses shader class variables, the shader won't compile. This is a convenient way to only use a part of a shader, but this isn't an optimization. The shader compiler already automatically removes any unnecessary variables.
Code example: static calls
shader StaticClass
{
    float StaticValue;
    float StaticMethod(float a)
    {
        return 2.0f * a;
    }
    // this method uses a
    float NonStaticMethod()
    {
        return 2.0f * StaticValue;
    }
};
// this shader class is fine
shader CorrectStaticCallClass
{
    float Compute()
    {
        return StaticClass.StaticValue * StaticMethod(5.0f);
    }
};
// this shader class won't compile since the call is not static
shader IncorrectStaticCallClass 
{
    float Compute()
    {
        return StaticClass.NonStaticMethod();
    }
};
// one way to fix this
shader IncorrectStaticCallClassFixed : StaticClass
{
    float Compute()
    {
        return NonStaticMethod();
    }
};