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.
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.
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.
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.
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.
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.
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.
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.
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
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 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.
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.
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
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.
Boolean statements can be asserted true with the assertion operator,
!. If the statement preceding the operator is
null, the current thread will end abruptly.
"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.
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.
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.