Introduction
Comparing General Programming Language
About
This page provides a comparison between many general purpose programming languages. General purpose here meaning any coding languages that can be used in a variety of use cases (although they need not necessarily be the best for all use cases). These languages should at minimum be Turing Complete. These languages can range from dynamic to static type checking, be compiled or interpreted, and have many different syntactic sugar. The goal is to show how each language approaches common semantic programming constructs such as bindings, conditionals, and loops. This will only focus on the language by itself and not any libraries (including any standard libraries) that it may use.
Languages
This page will have 3 languages you may switch between and compare.
Introduction to each of the supported languages. Also includes a numbered list of sources referenced.
// Sources and information about the C# language
// [1]: https://learn.microsoft.com/en-us/dotnet/csharp/
//
# Sources and information about the Python language
# [1]: https://docs.python.org/3/reference/index.html
# [2]: https://peps.python.org
#
// Sources and information about the Rust language
// [1]: https://doc.rust-lang.org/reference/index.html
// [2]: https://doc.rust-lang.org/rustdoc
//
The current version for each of the languages are defined in the table.
Language Name | Earliest Working Version | Latest Working Version |
---|---|---|
C# | ??? | 8.0 |
Python | ??? | 3.7 |
Rust | ??? | 1.64.0 |
Unless otherwise noted as a comment in the code, all code snippets should work with any version between the earliest and latest working versions for the associated language.
Comments
These are pieces of code that are generally ignored by the compiler or interpreter. Comments help programmers with providing extra information about the code without executing it.
Line Comments
Line Comments between language
// This is a single line comment
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/comments
# This is a single line comment
# Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#comments
// This is a single line comment
// Source [1]: https://doc.rust-lang.org/reference/comments.html#non-doc-comments
All line comments produce no output
Line comments are comments that run from the start of some symbol to the end of the line. Anything placed between will be ignored or removed when running the program. Once the line terminates, the comment also terminates, allowing the program to resume processing code after.
Start Symbol | Languages |
---|---|
// | C#, Rust |
# | Python |
Block Comments
Block Comments (or equivalent) between language
/*
This
is
a
block
comment
Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/comments
*/
"""
This
is
a
multi-line
string
(Not a true block comment but equivalent)
Can use either triple single quote (') or triple double quote (")
Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
-> see "longstring" definition
"""
/*
This
is
a
block
comment
Source [1]: https://doc.rust-lang.org/reference/comments.html#non-doc-comments
*/
All block comments produce no output
Block comments are comments that run from a certain start symbol to an end symbol. This means that comments can cover a small span of text (such as a single word within the same line) or a large span of text (such as a comment that spans multiple lines). Block comments can also be nested within themselves.
Has Block Comments? | Languages |
---|---|
Yes, Directly | C#, Rust |
Sort of, Indirectly | Python |
No |
Start Block Comment Symbol | Start Block Comment Symbol | Languages |
---|---|---|
/* | */ | C#, Rust |
For languages don't directly have block comments, these are conventional alternative:
Block Comment Alternative | Languages |
---|---|
Multi-Line Strings | Python |
Documentation Comments
Documentation comment examples
/// <summary> This is a single line documentation comment. </summary>
/** <summary>
This is a multiple
line documentation comment.
This can apply to any class and its members.
Uses XML markup for formatting.
Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/
</summary>
*/
""" This is a documentation comment applied to class, function or module when it is the first expression inside.
Source [1]: https://docs.python.org/3/glossary.html#term-docstring
Source [2]: https://peps.python.org/pep-0257/
Uses ReStructureText markup for formatting
Source [2]: https://peps.python.org/pep-0287/
"""
//! This is a outer line documentation comment
/*! This is an outer block documentation comment.
Applies to the parent item of this comment.
*/
/// This is an inner line documentation comment
/** This is an inner block documentation comment.
Applies to the item after this comment.
Uses Markdown for formatting.
*/
// Source [1]: https://doc.rust-lang.org/reference/comments.html#doc-comments
// Source [2]: https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html
Comments that document your code outside of the source code and are generally used to generate documentation. Not all languages have this facility built into their compiler or interpreter.
Has Documentation Comments | Languages |
---|---|
Yes | C#, Python, Rust |
No |
Documentation Markup Language | Languages |
---|---|
CommonMark Markdown | Rust |
ReStructureText | Python |
XML | C# |
Token
These are the smallest meaningful value known by the program. They often take the form of literal values, identifiers, and reserved keywords and operators. There are many different kinds of tokens unique to each programming language, so this section will focus on the general categories often found between languages.
Tokens are created during the lexing stage of the parser.
Literal Tokens
These tokens are parsed as the exact fixed value they represent and hold no other meaning beyond themselves. They often represent a value of basic types defined in the program. See Types Section for more details on this.
Boolean Literal
Example boolean literal values across languages
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/bool#literals
// True and False Literals
true
false
# Source [1]:
# - https://docs.python.org/3/library/constants.html#False
# - https://docs.python.org/3/library/constants.html#True
# True and False Literal - Constants in Python
True
False
// Source [1]: https://doc.rust-lang.org/reference/expressions/literal-expr.html#boolean-literal-expressions
// True and False Literal
true
false
These are literal values which might eventually become boolean value inside a program. Generally, one represents the concept of "true" and the other the concept of "false".
True Keyword | False Keyword | Languages |
---|---|---|
true |
false |
C#, Rust |
True |
False |
Python |
Numeric Literal
Example numeric literal values across languages
// Integral Literal
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types#integer-literals
0
42
-1
100_000
// Floating Point Literal
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types
3.14
-2.71
# Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#numeric-literals
# Python has 3 kinds of numeric literals: Integer, Floating Point, and Imaginary
# Integer Literal
# Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#integer-literals
0
42
-1
100_000
# Floating Point Literal
# Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#floating-point-literals
3.14
-2.71
# Imaginary Literal
# Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#imaginary-literals
1j
8.32j
// Source [1]:
// - https://doc.rust-lang.org/reference/tokens.html#numbers
// - https://doc.rust-lang.org/reference/tokens.html#number-literals
// Integer Literal
// Source [1]: https://doc.rust-lang.org/reference/tokens.html#integer-literals
0
42
-1
100_000
// Floating Point Literal
// Source [1]: https://doc.rust-lang.org/reference/tokens.html#floating-point-literals
3.14
-2.71
These are any literal tokens which may eventually become a numeric value inside the program. These are used to represent any kind of number including integral numbers and real numbers, and can also be in represented in different bases from decimal, such as binary and hexadecimal.
One kind of distinction a language can make is whether floating point numbers and integers are treated as separate kinds of literal values.
Float-Integer Distinction | Languages |
---|---|
Yes | C#, Python, Rust |
No |
Literal Text
Example textual literal values across languages
// Character Literal
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure#6455-character-literals
'a'
// String Literal
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure#6456-string-literals
"Hello"
# String Literal
# Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
# Python does not distinguish between characters and strings
# Characters are just strings of length 1
'a'
"Hello"
// Character Literal
// Source [1]: https://doc.rust-lang.org/reference/tokens.html#character-literals
'a'
// String Literal
// Source [1]: https://doc.rust-lang.org/reference/tokens.html#string-literals
"Hello"
These are literal values which might eventually become text value inside a program.
Char-String Distinction | Languages |
---|---|
Yes | C#, Rust |
No | Python |
Char Start Symbol | Char End Symbol | Languages |
---|---|---|
' |
' |
C#, Rust |
" or ' |
" or ' |
Python |
String Start Symbol | String End Symbol | Languages |
---|---|---|
" |
" |
C#, Rust |
" or ' |
" or ' |
Python |
Keyword Token
Keywords are tokens that have specific meaning in the language. The table show the total number of keywords found in the language (though not all are strictly used).
Language | Number of Keywords |
---|---|
C# | 120 |
Python | 38 |
Rust | 54 |
Strict Keyword
Example of strict keywords
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/
// Each keyword is separated by comma (,)
abstract , as , base , bool , break , byte , case , catch , char , checked , class ,
const , continue , decimal , default , delegate , do , double , else , enum , event ,
explicit , extern , false , finally , fixed , float , for , foreach , goto , if ,
implicit , in , int , interface , internal , is , lock , long , namespace , new , null ,
object , operator , out , override , params , private , protected , public , readonly ,
ref , return , sbyte , sealed , short , sizeof , stackalloc , static , string , struct ,
switch , this , throw , true , try , typeof , uint , ulong , unchecked , unsafe , ushort ,
using , virtual , void , volatile , while
# Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#keywords
# Each keyword is separated by comma (,)
and , as , assert , async , await , break , class , continue , def , del ,
elif , else , except , False , finally , for , from , global , import ,
if , in , is , lambda , not , None , nonlocal , or , pass , raise ,
return , True , try , while , with , yield
// Source [1] https://doc.rust-lang.org/reference/keywords.html#strict-keywords
// Each keyword is separated by comma (,)
as , async , await , break , const , continue , crate , dyn , else , enum ,
extern , false , fn , for , if , impl , in , let , loop , match , mod ,
move , mut , pub , ref , return , self , Self , static , struct ,
super , trait , true , type , unsafe , use , where , while
Strict keywords are always treated as keywords. When parsing/lexing, these words can never be treated as an identifier directly.
Contextual Keyword
Example of contextual keywords across languages
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/#contextual-keywords
// Each keyword is separated by comma (,)
add , and , alias , ascending , args , async , await , by , descending , dynamic , equals , file , from ,
get , global , group , init , into , join , let , managed , nameof , nint , not , notnull , nuint , on ,
or , orderby , partial , record , remove , required , scoped , select , set , unmanaged , value , var ,
when , where , with , yield
# Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#soft-keywords
# This is since version 3.10
# Each keyword is separated by comma (,)
_ , case , match
// Source [1]: https://doc.rust-lang.org/reference/keywords.html#weak-keywords
// Each keyword is separated by comma (,)
dyn , union , 'static
These are any keywords that are sometimes keywords when in a specific context.
Identifier Token
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure#643-identifiers
example
ident_1
_ident2
// Keyword as identifier
@if
# Source [1]: https://docs.python.org/3/reference/lexical_analysis.html#identifiers
example
ident_1
_ident2
// Source [1]: https://doc.rust-lang.org/reference/identifiers.html
example
ident_1
_ident2
// Keyword as identifier
r#if
These are the name that can bind to values or other names. Generally, only names not already keywords are considered identifier. Some languages can treat keywords as identifiers through a special prefix.
Type
A data type represents a set of all valid values that are possible and operations/functions one can apply to them. Data types act as an abstraction over and provide meaning to the underlying byte representation.
We can classify types into two categories: atomic and composite.
Has Types | Languages |
---|---|
Yes | |
Unityped | |
No |
Type Checking | Languages |
---|---|
Compile Time (Static) | C#, Rust |
Runtime (Dynamic) | Python |
Type Declaration | Languages |
---|---|
Explicit | C# |
Inferred | Rust? |
Implicit | Python |
In the next sections, we will only go over types that are directly available (that is, types that do not depend on other files nor user definition).
Atomic Types
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types
// List of data types separated by comma ( , )
bool, byte, sbyte, char, decimal, double, float,
int, uint, nint, nuint, long, ulong, short, ushort,
// void - act as a type for function that returns nothing
# Source [1]: https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy
# List of data types separated by comma ( , )
None, NotImplemented, Ellipsis,
# Sub-classes of Number supertype
int, bool, float, complex
// Source [1]: https://doc.rust-lang.org/reference/types.html
// List of data types separated by comma ( , )
bool,
// Numeric
i8, u8, i16, u16, f32, i32, u32, f64, i64, u64
// Textual
char
These are all types that have values which do not hold other values. At a low level, all types are just some way of representing a pattern of byte(s). The idea of these types is that they provide the fundamental units for the type system.
Composite Type
// Source [1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types
// List of data types separated by comma ( , )
object, string, dynamic
# Source [1]: https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy
# List of data types separated by comma ( , )
# Sequence types
str, bytes, bytearray, list, tuple,
# Set types
set, frozenset,
# Mapping Types
dict,
# Class and object
class, object
# Slice
slice,
# Functions, Generators, Coroutines, and Async functions
// Source [1]: https://doc.rust-lang.org/reference/types.html
// List of data types separated by comma ( , )
struct, enum, union,
// Tuple, Array, Slice,
// References, Raw Pointer, Function Pointer,
// Trait, Impl
These are types representing values that hold other values. This means that other types are needed.
Expression
Expressions are a combination of tokens that evaluate to some value. Expressions may or may not necessarily change the state of the program after being evaluated.
Statement
Statements are a combination of tokens that change the state of the program when executed. Statements may or may not produce results after execution.
Binding
A binding takes identifiers and relate that to an expression or value.
Variable
bool a = true;
a = True
// Immutable variable
let a: bool = true;
let b = false;
// Mutable variable
let mut c: bool = true;
let mut d = false;
Variable bindings take a value or the result of an expression and associate an identifier with it. Once bound, the variable may be allowed to change values later on. In dynamic languages, they may also be allowed to change types.
Binding Operator | Languages |
---|---|
= |
C#, Python, Rust |
Variable Type | Languages |
---|---|
Always required | C# |
Optional, type inferred | Rust |
Optional, type hinting | Python |
Type Location | Languages |
---|---|
Before identifier | C# |
After identifier : |
Rust, Python |
Variable default mutability | Languages |
---|---|
Mutable (changable) | C#, Python |
Immutable (not changable) | Rust |
Binding can change types | Languages |
---|---|
Yes | Python |
No | C#, Rust |
Constant
const bool A_CONST = true;
# Python has no enforceable constant
# By conventions, identifiers in SCREAMING_SNAKE_CASE usually signify constants
A_CONST = True
const A_CONST: bool = true;
Constant binding takes a value or the result of some constant expression and associates it with an identifier. Once bound, the identifier cannot change values for the life of its scope.
Prefix Keyword | Languages |
---|---|
const |
C#, Rust |
None | Python |
Binding Operator | Languages |
---|---|
= |
C#, Python, Rust |
Constant Type | Languages |
---|---|
Always required | C#, Rust |
Optional, type hinted | Python |
Type Location | Languages |
---|---|
Before identifier | C# |
After identifier : |
Rust, Python |
Callable Unit
void NoParameterFunction(){}
void SingleParameterFunction(bool param){}
void MultipleParameterFunction(int param1, int param2){}
def no_parameter_function():
pass
def single_parameter_function(param):
pass
def multiple_parameter_function(param1, param2):
pass
fn no_parameter_function() -> () {}
fn single_parameter_function(param1: i64) -> () {}
fn multiple_parameter_function(param1: i64, param2: i64) -> () {}
Also known functions, procedures, subroutines. These bind an identifier to some block of code. They can take values in as parameter as inputs to the function, in which identifiers of the same name may be referred inside the code block, and return values back out.
Function Definition Keyword | Languages |
---|---|
def |
Python |
fn |
Rust |
No Keyword | C# |
Parameters Typing | Languages |
---|---|
Always required | C#,Rust |
Optional, type hint | Python |
Parameter Types Required | Languages |
---|---|
Always | C#, Rust |
Optional, type hint | Python |
Resulting Typing | Languages |
---|---|
Always required | C# |
Almost always | Rust (unless () (unit type)) |
Optional, type hint | Python |
Resulting Type Location | Languages |
---|---|
Before identifier | C# |
After parameters -> |
Rust |
After parameters : |
Python |
Control Flow
Control flow code determines how code flows in the program. According to the structured program theorem, there are only three constructs needed to build any Turing-equivalent machine: sequence, selection, and repetition.
Sequence
// S1;S2
/*
S0;
{
S1;
S2;S3;
S4;
}
S5;
*/
# S1\nS2
# or
# S1;S2
"""
S0
# implied block
S1;
S2
S3;S4
S5
"""
// S1;S2
/*
S0;
{
S1;
S2;S3;
S4;
}
S5;
*/
A sequence defines how one can separate two statements from each other. The idea is for the program to execute the first statement and then execute the next statement.
Sequence Separator | Languages with this as Primary | Languages with this as Secondary |
---|---|---|
; |
C#, Rust | Python |
newline | Python |
Multiple sequences can be pulled together into a block.
Sequence Open Block | Sequence Close Block | Languages |
---|---|---|
{ |
} |
C#, Rust |
Indent | Dedent | Python |
Selection
Also known as conditional. For this control flow, it can branch out into different code sequences depending on certain conditions.
Single Branch
Example of single branch conditional
bool condition = true; // or false
if(condition){
// Code here run when condition is true
}
condition: bool = True # or False
if condition:
# Code here run when condition is true
pass
let condition: bool = true; // or false
if condition {
// Code here run when condition is true
}
This conditional branches to a block of code if some condition is true, and is skipped if the condition is false. The true branch meets back to the main path of execution. This kind of conditional can be used to implement an optional path of execution when some condition is met.
Branching Keyword | Languages |
---|---|
if |
C#, Python, Rust |
Structure | Languages |
---|---|
if (<condition_expression>) {<true_block>} |
C#, Rust |
if <condition_expression> {<true_block>} |
Rust |
if <condition_expression>: INDENT <true_block> DEDENT |
Python |
Branch With Default (if-else)
Example of branch with default conditional
bool condition = true; // or false
if(condition){
// Code runs here when conditional is true
}
else {
// Code runs here when conditional is false
}
condition = True # or False
if condition:
# Code runs here when conditional is True
pass
else:
# Code runs here when conditional is False
pass
let condition = true; // or false
if condition {
// Code runs here when conditional is true
}
else {
// Code runs here when conditional is false
}
This modifies a conditional by creating a branch for code after any conditions prior to it is false. Think of this as the default case. Note that unlike having code outside the conditional, the code only runs inside this default case only when it has not taking any path previously.
Default Keyword | Languages |
---|---|
else |
C#, Python, Rust |
Structure After If-Condition | Languages |
---|---|
else {<false_block>} |
C#, Rust |
else: INDENT <false_block>} DEDENT |
Python |
Multiple Branches
Example of multiple branch:
bool condition_1 = false; // or true
bool condition_2 = true; // or false
if(condition_1){
// Code runs here when conditional_1 is true (regardless of condition_2)
}
else if (condition_2){
// Code runs here when condition_1 is false and condition_2 is true
}
else {
// Code runs here when both condition_1 and condition_2 are false
}
condition_1 = False # or True
condition_2 = True # or False
if condition_1:
# Code runs here when conditional_1 is True (regardless of condition_2)
pass
elif condition_2:
# Code runs here when condition_1 is false and condition_2 is true
pass
else:
# Code runs here when both condition_1 and condition_2 are false
pass
let condition_1 = false; // or true
let condition_2 = true; // or false
if condition_1 {
// Code runs here when condition_1 is true (regardless of condition_2)
}
else if condition_2 {
// Code runs here when condition_1 is false and condition_2 is true
}
else {
// Code runs here when both condition_1 and condition_2 are false
}
In this conditional, one can add an alterative path that occurs after checking the first condition and is bound by some other condition. This can be chained indefinitely to allow multiple mutually exclusive paths.
Alternative Keyword | Languages |
---|---|
else if |
C#, Rust |
elif |
Python |
Conditional Expressions
Also known as ternary operator.
Example of conditional expressions
bool cond = true;
var true_val = 1;
var false_val = 22;
var res = cond ? true_val : false_val;
cond = True
true_val = 1
false_val = 22
res = true_val if cond else false_val
let cond = true;
let true_val = 1;
let false_val = 22;
let res = if cond {true_val} else {false_val};
Conditional expressions are similar to conditional statements, where the branch that is chosen is based on some truth value of a condition. The difference is that conditional expressions can return values from them. Some language have a special operator that does this called the ternary operator. One specific constraint condition expression have is that there must always be a default part, as there must always be a value returned by the expression.
Structure | Languages |
---|---|
<condition_expression> ? <true_expression> : <false_expression> |
C# |
<true_expression> if <condition> else <false_expression> |
Python |
if <condition> {<true_expression>} else {<false_expression>} |
Rust |
Repetition
Also known as iteration or looping.
Language | Conditional Loop | Infinite Loop | Count Loop | Collection Loop |
---|---|---|---|---|
C# | Yes | Possible | Yes | Yes |
Python | Yes | Possible | Possibe | Yes |
Rust | Yes | Yes | Possible | Yes |
Condition Loop
These are loops that are controlled by conditions. There are generally to kinds of conditional loop based on when the check occurs, at the beginning of the loop and at the end.
While Loop
Example of While Loop
bool condition = true;
while(condition){
// Run code inside when true
}
condition = True
while condition:
# Run code inside when true
pass
let condition: bool = true;
while condition {
// Run code inside when true
}
In this condition controlled loop, the condition is checked before the loop code is run. If the condition is false, the code is skipped, even if it has never ran. If the condition is true, the code inside is executed. Usually, the condition has some part of its expression that is dynamic and changes when in the loop.
While Loop Syntax | Languages |
---|---|
while(<condition>) {<loop-code>} |
C#, Rust |
while <condition> {<loop-code>} |
Rust |
while <condition>: INDENT <loop-code> DEDENT |
Python |
Infinite Loop
Example of Infinite Loop (or closest alternative)
csharp for(;;) { // Do this forever. }
while True:
# Do this forever
pass
loop {
// Do this forever
}
An infinite loop is a loop that has no explicit stop condition, meaning that the loop will run without end. To stop an infinite loop, one will require using some mechanism to stop the loop.
Structure | Languages |
---|---|
loop |
Rust |
Possible Alternative | Languages |
---|---|
while-true |
C#, Python, Rust |
empty-for |
C# |
Iteration
Count Controlled Loop
A count-up look going from 0 to 10 (not including 10)
for(int i = 0; i < 10; i++){
Console.WriteLine(i);
}
for i in range(0,10):
print(i)
for i in 0..10 {
println!(i);
}
These kind of loops are controlled by a range of numbers.
Keyword | Langage |
---|---|
for |
C#, Python, Rust |
Structure | Langauge |
---|---|
for(start, end, next) |
C# |
for <variable> in <range_iterable> |
Python, Rust |
Count Controlled Loop
A count-up look going from 0 to 10 (not including 10)
var numbers = [1,2,3,4,5];
foreach(var number in numbers){
Console.WriteLine(number);
}
numbers = [1,2,3,4,5]
for number in numbers:
print(number)
for i in 0..10 {
println!(i);
}
These kind of loops are controlled by a collection of values.
Keyword | Langage |
---|---|
foreach |
C# |
for |
Python, Rust |
Structure | Langauge |
---|---|
for(<type> <variable> in <collection>) |
C# |
for <variable> in <range_iterable> |
Python, Rust |