Use The Source

These are guidelines for code style and quality that we follow at UseTheSource.

General

  • we use Google’s open source style guides as the following items are extensions or deviations from this guide.
  • maximum line length: 100
  • no tabs for indentation: 4 spaces.
  • comments explain any otherwise implicit intent or purpose; otherwise code must speak for itself.

Java

  • all public classes are documented with Javadoc to state their intent and purpose.
  • all public methods are documented with Javadoc to state their intent and purpose.
  • package names are io.usethesource.<project>.<sub>
  • use the @Override annotation everywhere it’s possible.
  • clean up all unused imports.

Rascal

  • all public functions have @synopsis tags in Rascal tutor format.
  • most public functions have @description and @examples tags in Rascal tutor format.
  • tools for languages reside in lang/<language name>/<sub?>/<tool name>.rsc
  • generic algorithms for analysis reside in analysis/<algorithm group>/<algorithm>.rsc
  • generic utilities (i.e. for communication) reside in utils/<utility>.rsc
  • names, unless mapped one-to-one from an external source, follow these rules:
    • references to instances like variables, constructor names, field names, functions, pattern variables, tag names all start with lowercase and continue with camelCaseStyle.
    • names of types, data, syntax, lexical, keyword, layout, and alias types, all start with a capital and continue with CamelCaseStyle.
    • constants are in ALL_CAPS
    • meaningful reserved names, such as if for the constructor name are not renamed to avoid the collision but escaped like so: \if. This holds for all names.
    • Abstract syntax trees use the typical names as declared in analysis::m3::AST: Declaration, Expression, Statement, Type, Modifier.
    • the source location of the original information is always stored in the field loc src=|unknown:///|
  • the default value for all fields of type loc is typically |unknown:// unless well motivated.
  • test functions are located inside the modules of the functionality they test. This is to improve cohesion and lower coupling and to enrich the online documentation with descriptive specifications.
  • functions used only for testing purposes are always private
  • small functions only used by one function are declared inside of the caller’s scope as much as possible.
  • local helper functions are otherwise made private
  • switch is avoided when pattern based dispatch is also possible, for future extensibility’s sake.
  • use nullary ADT constructors as “enums”, never strings.
  • use loc source locations as references, qualified names or general identifiers; to avoid strings, captured variables or other fancy usages of first class functions.
  • use relations over maps where possible, for future generalizability where suddenly the mapping is not many-to-one anymore. The underlying datastructures for relations gracefully expand.
  • Staging before parametrization: introduce an intermediate datatype or relation instead of adding (higher order) parameters to introduce algorithmic variability.
  • Positional fields of ADT constructors, when they have a src origin field are always ordered by their original position from left you right. The same holds for lists of ADT constructors; they remain ordered by their src field, unless the elements do not originate from the same source file anymore.
  • Collect and reason about algorithmic answers using relational calculus: union, intersecting, composition, comprehensions, recursion, solve statement; over use the of higher order first class functions and closures. Immutable relations are easier to debug, much easier to extend, and have fewer bugs in general due to equational reasoning that you loose when using closures over mutable state.
  • With respect to error handling:
    • the Message ADT is for user expected errors detected in an object language: type checking, linting, etc. which can be reported in an IDE.
    • we collect messages in list[Message] sorted by file offset and grouped by source file.
    • functions rather return void than return an error code. Instead they throw an exception value when an internal error is detected.
    • exception values are typically a constructor of RuntimeException from the Exception module. Either use an existing constructor or add your own.
  • Progress is reported through the util::Monitor API. This integrates with all programming environments.
  • Interactive UI is built with HTML and JavaScript, using the built-in app server off the REPL on the terminal, the showInteractiveContent app server of the IDE or util::WebServer. You can use lang::html and lang::json to streamline this. The Salix library is also recommended.