Subjective-C

From Esolang
Jump to navigation Jump to search

Subjective-C is a joke programming language designed by User:Proxxa to be wholly unintuitive and redundant in its features. One such redundancy is the feature of scopes. Subjective-C is strongly-typed, high-level, and object-oriented.

Naming

Contrary to its name, Subjective-C has nothing to do with the C language. In that respect, it has more to do with Java. The name was given intentionally to both mislead one into making this assumption and to be parallel in naming to "Objective-C".


Hello World Example

Before delving into the intricacies of the language, the following Hello World example and the following explanation will describe a simple program in Subjective-C

export-pkg helloworld.   Export file as the helloworld package
import-pkg stdio.           Import standard IO
import-pkg immutable.  Import immutability

unprotected static object HelloWorld imports stdio and immutable accessible-from *?
  static immutable-value string HELLOCONST accessible-from mainscope is "Hello, World!". Declare a constant value

  unprotected static impure method mainMethod with array<string> arguments imports stdio uses-scope mainscope accessible-from *?
    call-method stdo from stdio with HELLOCONST. Call standard output
    end method.
  end object.

The export-pkg keyword describes what package the current file is accessible from. Package names must be lowercase and use only alphanumeric characters. The . character is used to dedicate the end of the line. All text after this character on the same line is ignored. import-pkg imports all unprotected, top-level objects from the described package. The stdio package encloses methods used for standard input/output. The immutable package allows the use of a decorator that marks a field of value as immutable.

The unprotected keyword decorates a type, method, or field as unprotected rather than the default of nonpublic. The static keyword decorates a type, method, or field as bound to its enclosing type rather than an instance of the type. This keyword is required on user-defined types and top-level methods. object designates a new user-defined type. The next string of space-delimited text is used as the identifier of the type. imports defines the packages usable within a scope. accessible-from defines what scopes a type, field, or method can be accessed from. Using an asterisk (*) is akin to a wildcard; the HelloWorld object is accessible from all scopes. The ? character signals the opening of a scope which spans multiple lines. It is used whenever the single-line ~ does not suffice.

immutable-value is a decorator from the immutable package which marks a field or value as immutable. string is a type which acts much like a primitive string of text. The characters in these strings are only one byte in length. The is keyword assigns a value to a field or variable.

method designates a method associated with a type or instance. The with both describes the arguments which a method takes in and what arguments a method is called with. uses-scope defines which scopes can be accessed from within a scope. The call-method keyword is placed before a method identifier in order to call it. from designates in which package to look for an identifier. The end keyword describes the end of a multi-line scope. It must be followed by the type of scope.

Language Features

Dual-Purpose Line Endings

Lines end with periods. They are required after instructions, and all succeeding text on the same line is ignored. Because of this, periods are also used to begin comments.

Packages

Subjective-C uses a packaging system to separate methods and types into containers. Each package in Subjective-C is its own file, and packages are entirely un-hierarchical.

Exporting Packages

When packages are exported, all the top-level, unprotected types, methods, and values are exported under the name declared by the export-pkg keyword. This keyword must be at the top of the file.

Importing Packages

To be used within a package, other packages must be both imported by the current package and any scopes using it. Packages must be imported at the top of the file, after the export-pkg statement with the import-pkg keyword. It must be then imported into a scope with the imports keyword. Specific identifiers cannot be imported; instead, all identifiers must be imported from a package.

Methods

Calling methods in Subjective-C has a particular syntax. They require a purity keyword, name, and accessible-from scope on each declaration. Optionally, they can take in arguments with the with keyword, import packages with the imports keyword, and specify return values with the gives keyword. Methods can then be called using the call-method keyword.

Return Values

Return types are specified on declaration using the gives keyword. In the function, the return value is given when the end method sequence is used by adding with <value> afterward.

pure static method doublesInteger with integer inputInteger accessible-from exampleScope?
  end method with inputInteger * 2.

Arguments

Arguments are specified using the with keyword on both declaration and calling.

impure static method mainMethod imports stdio and stdtypes uses-scope exampleScope accessible-from *?
  integer shouldBeFour is call-method doublesInteger with 2.
  string stringified is call-method stringifyInteger with shouldBeFour.
  call-method stdo from stdio with stringified. Should output "4" to stdout.
  end method.

pure static method doublesInteger with integer inputInteger accessible-from exampleScope?
  end method with inputInteger * 2.

Scopes

Scoping serves to further categorize pieces of the language. The word "scope" can have two meanings when referring to Subjective-C:

  • The code within a type, method, or thread.
  • A group given to an identifier to limit what scopes can access it. To avoid ambiguity, this will be referred to as a "scope group" in this section.

The accessible-from keyword designates which scope group(s) this identifier belongs to. The * wildcard allows an identifier to belong to all scope groups. This is required for all identifiers, and the identifier can be given multiple groups using the and keyword.

The uses-scope keyword designates which scope group(s) this scope may access. If the scope does not specify which scope groups it accesses, it will instead only be able to access the * scope group.

Assertion

Boolean statements can be asserted true with the assertion operator, !. If the statement preceding the operator is false or null, the current thread will end abruptly.

Threads

"Threads" are special methods which run on their own processor threads. Rather than using the method type, they use the thread type. Due to their strange behavior, it is best to understand their use with an example.

pure thread myThread accessible-from funScope with string immutable-value x? 
  . Assert the existence of x
  x!=null!
  . Do other things…
  end thread. End the thread normally

impure method funMethod uses-scope funScope imports immutable accessible-from *?
  string immutable-value myImmutableVariable is "A constant!".
  spawn myThread with myImmutableVariable.
  end method.

Due to Subjective-C's lack of conditional statements such as if and else, threads which begin with assertions are the recommended way to ensure the validity of a Boolean statement before executing instructions when such a statement would normally be entered into an if statement. This is an intentionally bad design choice.

Purity Keywords

Subjective-C enforces function purity by the use of a keyword placed before the method/thread keyword. The "pure" keyword describes a function as "pure," and the "impure" keyword describes a function as "impure." Pure functions cannot call impure functions or modify the state of the instance which the function is bound to. It should be noted that all functions which make system calls are counted as impure. As such, the entry point of a program is likely to be impure unless the program has no output. This feature is intentionally pointless.

pure static method myPureMethod accessible-from pureMethodScope gives integer?
  end method with 3. Return the integer 3

. stdio and stdtypes must be imported into the current package for this method
impure static method myImpureMethod uses-scope pureMethodScope imports stdio and stdtypes accessible-from *?
  integer pureMethodOutput is call-method myPureMethod.
  string stringifiedOutput is call-method stringifyInteger from stdtypes with pureMethodOutput.
  call-method stdo from stdio with 
  end method.

Subjectivity

Subjective-C is entirely subjective. That is, if a piece of code seems to fit the style of Subjective-C, it most likely is Subjective-C. Because of this, it is impossible to create a compiler or interpreter for Subjective-C. In fact, it is recommended to never create such an implementation due to the number of poor design choices. It is also recommended that anyone who views this page adds a wholly unintuitive feature to this page. For this purpose, try writing an imaginary program in Subjective-C using features and designs of examples already given by this page.

In essence, Subjective-C is in the eye of the beholder. While this page may give examples of Subjective-C, some may see all the given examples as invalid Subjective-C code.