# Coding style

##

Introduction

This chapter intends to desribe the coding style and conventions applied in Yacas in order to make sure the engine always returns the correct result. This is an attempt at fending off such errors by combining rule-based programming with a clear coding style which should make these mistakes impossible.

##

Interactions of rules and types

One unfortunate disadvantage of rulebased programming is that rules can sometimes cooperate in unwanted ways.

One example of how rules can produce unwanted results is the rule `a*0=0.` This would always seem to be true. However, when a is a vector, like `a:={b,c,d}` , then `a*0` should actually return `{0,0,0}` , that is, a null vector. The rule `a*0 -> 0` actually changes the type of the expression from a vector to a integer! This can have severe consequences when other functions using this expressions as an argument expect a vector, or even worse, have a definition of how to work on vectors, and a different one for working on numbers.

When writing rules for an operator, it is assumed that the operator working on arguments, like Sin or *, will always have the same properties regardless of the arguments. The Taylor series expansion of Sin(a) will be the same regardless of whether a is a real number, complex number or even a matrix. The same trigonometric identities should hold for Sin, regardless of the type of a, too.

If a function is defined which does not adhere to these rules when applied to another type, a different function should be defined.

By default, if a variable has not been bound yet, it is assumed to be a number. If it is in fact a more complex object, like a vector, then you can declare a to be an 'incomplete type' vector, using Object("IsVector",a). This subexpression will evaluate to a if and only if a is a vector at that moment of evaluation. Otherwise it returns unevaluated, and thus stays an incomplete type.

So this means the type of a variable is numeric unless otherwise stated by the user, using the "Object" command. No rules should ever work on incomplete types. It is just meant for delayed simplification.

The topic of implicit type of an object is important, since many rules often implicitly need to be able to assume something is a number.

##

Ordering of rules

The implementor of a rule set can specify the order in which rules should be tried. This can be used to let the engine try more specific rules before trying less specific rules.

The problem mentioned above with a rule for vectors and scalars could be solved by making two rules:

a*b (b a vector) -> return vector of each component multiplied by a.

a*0 -> 0

So vector multiplication would be tried first.

The ordering of the precedence of the rules in the standard math scripts is currently:

- 50-60: Args are numbers: directly calculate. These are put in the beginning, so they are tried first. This is useful for quickly obtaining numeric results if all the arguments are numeric already, and symbolic transformations are not necessary.
- 100-199: tautologies. Transformations that do not change the type of the argument, and are always true.
- 200-399: type-specific transformations. Transformations for specific types of objects.
- 400-599: transformarions on scalars (variables are assumed to be scalars). Meaning transformations that can potentially change the type of an argument.