-
-
Notifications
You must be signed in to change notification settings - Fork 4
inventions
Not new inventions, but cherry-picking the most beautiful, powerful and sane features of other modern programming languages, especially Julia, Swift, Crystal and Kotlin but definitely not Java. Those adoptions include it keyword in closures, multiple dispatch, optional typing, self hosting (secondary goal to not bias language design)
Merge the concept of type and variable (name) in simple functions:
To assign a photo to a contact:
contact.image = photo
Here both photo and contact act as matching types and as variable identifiers. What sounds pretty complicated is very obvious in code (see above).
The precise semantics of the above function can be specified later, for example by declaring
a photo is an image
given maybe image type is UIimage
As in other languages, class types are capitalized (not just by convention)
(In cases of ambiguity) one can explicitly access types as such:
image.kind = Photo
image.kind = photo type
image.kind = type of photo
type of photo
resolves to Photo type regardless of whether a photo variable is in context or not.
Consistent grouping
newline groups harder than semicolon, therefore one liners like
suffix operator ⁿ := c=it;while n-->0 : c*=it; c
don't need braces.
Inverse dot: a.b is b of a
Also works in assignments and definitions:
square of number = it*it
Which is just the bracket less version of:
square(number) = it*it
In fact this is the preferred way to define (property) methods out of scope. In scope it would look like this:
Number {
Square = it*it
}
Todo it ambiguity in nested scopes
In contemporary dynamic programming languages there is often uncertainty what exactly a for loop iterates over:
for(x in y)
or for(x of y)
can mean:
for key in map: print it
for key, value in map: print key
for pair in map: print pair.key
Thus in angle loop iteration takes type hints:
for each byte in "Hello" : print byte
for each char in "你好" : print char
for codepoint1 in "你好" : print it
//how? simple: each takes a type as polymorphic argument:
string{
each(byte){return ...}
each(char){return ...}
each(grapheme){return ...}
}
x in y is an alias for y.x to access properties and functions.
for is a function that takes a list or an iterator and a block:
for(list, block):=i=list.size|while (i-->0) block(list [i])
Angle has the goal to be maximally welcoming to beginners,
yet mathematically sound and compatible to old programming languages where possible. Thus
{1 4 9}#3 is 9
which is identical to old style 0-based indexing
nums={1 4 9};nums[2] == 9
The it keyword in closures was a great invention ( first seen in Kotlin?) we extend this to much wider user cases, in fact it becomes the catch all keyword for the current object, variable or result; where Julia has ans etc.
square of number = it*it
Often it is identical to this/self unless there is another object in scope, in which this/self are to be used. What might seem slightly complicated comes very naturally when applied.
In cases where there is an ambiguity we have
Instead of throwing a compile error when faced with ambiguities, the compiler simply asks for the intended meaning and, if desired, writes that resolution to a cache, to a comment or even back to the source code.
'to' keyword to define verb functions
To square a number: return it times it
To square a number: return it times it
3.squ<tab>
3.square is 9
To square a number: return it times it
x is number 3
square of <tab>
square of x is 9
Reserve all pronouns propositions and particles as Keywords Once a word is defined as class it becomes a semi keyword in that properties/methods get assigned to the class:
Integers are numbers
Number a = 3
square of number = it*it
In data, lists and certain execution contexts, symbols don't need to be quoted:
person {
name: James
age: 35
}
This format is more pleasant than json yet free of ambiguity
Indexing with '#'
Colors = red, green, blue
Color#1 is red
friends = { peter{wife:jule} karl{existent:false}}
- peter from friends == friends[peter]
- peter of friends == friends[peter]
- peter in friends == friends[peter]
- friends.peter == friends[peter]
Gap filling : Use local variables as missing arguments to functions
f(x):=x*x
x=7;f() # 7
Gap Feeding of missing arguments with locals in function calls
to integrate a function from a to b ...
from = 1
to = 2
integrate sin # feeds locals as arguments
Bad idea?
Each operator automatically works with assignment: x ⊛= b
is always a shorthand for x = x ⊛ b
.
If x was not mutable an error occurs at compile time.
Since Angle is inspired by English, each type declaration generates a plural form with tailing 's':
number => numbers==number[]==[number]
(swift style)
property's
's
keyword:
peter's friend == friend of peter == peter[friend]
All functions are automatically broadcasting on lists and pair values:
square number=number*number
square [1 2 3] == [1 4 9]
square [a:1 b:2 c:3] == [a:1 b:4 c:9]
delete file = run `rm $file.name`
delete files in ls / # 🧐
Use allall keyword and polymorphism if fine-grained behavior is required:
print numbers = print "one at a time please"
print number = printf("%d",d)
print [1 2 3] = "one at a time please"
print all [1 2 3] = "1" "2" "3"
In angle the is
operator acts as assignment/declaration unless it appears in a condition or expression:
a=123
if a=123 print "ok"
print a=123 // true
mutating modifying member functions are to be suffixed with an exclamation point (by the linter?)
class string{
data chars
void upper!{
chars[0]=chars[0].upper()
}
variables can be force mutated by adding an exclamation point
x="test"
x.upper!
# same as x = x.upper()
The result of pure functions must be used or explicitly assigned to '_' as in rust.