Using the Python Interpreter as a Reference

T

Travis Parks

Hello:

I am currently working on designing a new programming language. It is
a compiled language, but I still want to use Python as a reference.
Python has a lot of similarities to my language, such as indentation
for code blocks, lambdas, non-locals and my language will partially
support dynamic programming.

Can anyone list a good introduction to the files found in the source
code? I have been poking around the source code for a little bit and
there is a lot there. So, I was hoping someone could point me to the
"good parts". I am also wondering whether some of the code was
generated because I see state transition tables, which I doubt someone
built by hand.

Any help would be greatly appreciated. It will be cool to see how the
interpreter works internally. I am still wonder whether designing the
language (going on 4 months now) will be harder than implementing it.

Thanks,
Travis Parks
 
C

Chris Angelico

I am currently working on designing a new programming language. It is
a compiled language, but I still want to use Python as a reference.
Python has a lot of similarities to my language, such as indentation
for code blocks, lambdas, non-locals and my language will partially
support dynamic programming.

If you want to use Python as a reference for designing your language,
look at the documentation. It's pretty decent on the subject of
language specs (you may find yourself reading a lot of PEPs as well as
the "normal" docs).

But for actual code - you may want to look at Cython. I've never used
it, but it compiles Python code to C (IIRC); that's more likely to be
what you're after.

What's your language's "special feature"? I like to keep track of
languages using a "slug" - a simple one-sentence (or less) statement
of when it's right to use this language above others. For example,
Python is optimized for 'rapid deployment'.

ChrisA
 
D

Dennis Lee Bieber

I don't think Python has a hard disk big enough to save all of it...
Since it would, technically, need to save it's own storage in order
to record the state of all the atoms, it becomes a recursive problem.
 
T

Travis Parks


The language, psuedo name Unit, will be a low-level language capable
of replacing C in most contexts. However, it will have integrated
functional programming features (tail-end recursion optimization,
tuples, currying, closures, function objects, etc.) and dynamic
features (prototypical inheritance and late binding).

It is a hybrid between C#, C++, F#, Python and JavaScript. The hope is
that you won't pay for features you don't use, so it will run well on
embedded devices as well as on desktops - that's to be seen. I'm no
master compiler builder, here.

The functional code is pretty basic:

let multiply = function x y: return x * y # automatic generic
arguments (integer here)
let double = multiply _ 2 # short-hand currying - inlined if possible
let doubled = [|0..10|].Apply(double) # double zero through 10

The dynamic code is pretty simple too:

dynamic Prototype = function value: self.Value = value # simulated
ctor
Prototype.Double = function: self.Value * 2 # self refers to instance
new Prototype(5).Double() # 10
new Prototype(6).Double() # 12
dynamic x = 5 # five wrapped with a bag
x.Double = function: self * 2
x.Double() # 10
dynamic y = 6
y.Double = x.Double # member sharing
y.Double() #12

The language also sports OOP features like are found in Java or C#:
single inheritance; multiple interface inheritance; sealed, virtual
and abstract types and members; explicit inheritance; extension
methods and namespaces.

The coolest feature will be its generics-oriented function signatures.
By default everything is generic. You apply constraints to parameters,
rather than specific types. For instance:

let Average = function values:
where values is ICountable<Integer32> IIterable<Integer32>
assert values.Count > 0 "The values list cannot be empty."
throws ArgumentException
returns Float64
let sum = 0
for value in values:
sum += value
return sum / values.Count # floating point division

As you can see, the function headers can be larger than the bodies
themselves. They support type constraints, assertions (argument
checking), exceptions enumeration, default parameters and return type
information. All of them can be left out if the type of arguments can
be inferred.

This will not be an overnight project. :)
 
A

Alan Meyer

Hello:

I am currently working on designing a new programming language. ...

I have great respect for people who take on projects like this.

Your chances of popularizing the language are small. There must be
thousands of projects like this for every one that gets adopted by other
people. However your chances of learning a great deal are large,
including many things that you'll be able to apply to programs and
projects that, at first glance, wouldn't appear to benefit from this
kind of experience. If you get it working you'll have an impressive
item to add to your resume.

I suspect that you'll also have a lot of fun.

Good luck with it.

Alan
 
T

Travis Parks

I have great respect for people who take on projects like this.

Your chances of popularizing the language are small.  There must be
thousands of projects like this for every one that gets adopted by other
people.  However your chances of learning a great deal are large,
including many things that you'll be able to apply to programs and
projects that, at first glance, wouldn't appear to benefit from this
kind of experience.  If you get it working you'll have an impressive
item to add to your resume.

I suspect that you'll also have a lot of fun.

Good luck with it.

     Alan

I've been learning a lot and having tons of fun just designing the
language. First, I get think about all of the language features that I
find useful. Then I get to learn a little bit how they work
internally.

For instance, functions are first-class citizens in Unit, supporting
closures. To make that happen meant wrapping such functions inside of
types and silently elavating local variables to reference counted
pointers.

Or, I realized that in order to support default arguments, I would
have to silently wrap parameters in types that were either set or not
set. That way calls to the default command could simply be replaced by
an if statement. It was a really subtle implementation detail.

It is also fun thinking about what makes sense. For instance, Unit
will support calling methods with named arguments. Originally, I
thought about using the '=' operator:

Foo(name="bob" age=64)

but, then I realized that the equals sign could be confused with
assignment. Those types of syntactic conflicts occur quite often and
lead to a lot of rethinking. Ultimately, somewhat good ideas get
replaced with much better ideas. I had been contemplating Unit for
months before the final look and feel of the language came into view.
It isn't what I started out imagining, but I think it turned out
better than I had originally planned.


Recently, I rethought how functions looked, since the headers were too
long:

alias Predicate = function<T> (value: & readonly T) throws()
returns(Boolean)
let Any = public function<T>
(values: & readonly IIterable<T>)
(?predicate: Predicate<T>)
throws() # ArgumentNullException inherits from UncheckedException
returns(Boolean): # this can be on one line
default predicate = (function value: true)
assert predicate != null "The predicate cannot be null."
ArgumentNullException
for value in values:
if predicate(value):
return true
return false

Most of the time, throws clauses, returns clauses and parameter type
constraints can be left off. Plus, now they can all appear on one
line. Assertions and default statements now appear in the body.
Assertions now optionally take a message and the exception type to
throw.

So, yeah, this has been an awesome project so far. I have dozens of
documents and I have been keeping up on a blog. I've even started
implementing a simple recursive descent parser just to make sure the
syntax doesn't conflict. Now it will be a matter of formally defining
a grammer and implementing the backend of the compiler... which I've
never done before. I have been thinking about compiling into a
language like C++ or C instead of assembler for my first time through.
 
C

Chris Angelico

I have been thinking about compiling into a
language like C++ or C instead of assembler for my first time through.

Yep, or any other language you feel like using as an intermediate. Or
alternatively, just start with an interpreter - whatever's easiest.
Compiling to C gives you a massive leg-up on portability; so does
writing an interpreter in C, as either way your language is easily
made available on every platform that gcc's been ported to.

As long as you're happy with the idea of building a massively language
that'll never be used by anybody but yourself, you can have immense
fun with this. And hey, Unit might turn out to be a beautiful niche
language, or even go mainstream.

But mainly, you'll have fun doing it. And if you're not having fun,
what's the use of living forever? (Oh wait, you're not a vampire from
Innistrad. Sorry about that.)

ChrisA
 
R

rusi

Hello:

I am currently working on designing a new programming language. It is
a compiled language, but I still want to use Python as a reference.
Python has a lot of similarities to my language, such as indentation
for code blocks, lambdas, non-locals and my language will partially
support dynamic programming.

Can anyone list a good introduction to the files found in the source
code? I have been poking around the source code for a little bit and
there is a lot there. So, I was hoping someone could point me to the
"good parts". I am also wondering whether some of the code was
generated because I see state transition tables, which I doubt someone
built by hand.

Any help would be greatly appreciated. It will be cool to see how the
interpreter works internally. I am still wonder whether designing the
language (going on 4 months now) will be harder than implementing it.

Thanks,
Travis Parks

- compiled language
- indentation based
- functional programming features

Looks like a description of Haskell. You may want to look there.

Back end: LLVM is gaining a lot of traction these days. Seems to give
best of both worlds -- compiling to C and to machine code
 
S

Sells, Fred

I'm looking at a variation on this theme. I currently use
Flex/ActionScript for client side work, but there is pressure to move
toward HTML5+Javascript and or iOS. Since I'm an old hand at Python, I
was wondering if there is a way to use it to model client side logic,
then generate the javascript and ActionScript. I don't see an issue
using custom python objects to render either mxml, xaml or html5 but I'm
not aware if anyone has already solved the problem of converting Python
(byte code?) to these languages? Any suggestions.
 
R

Rick Johnson

Hello:

I am currently working on designing a new programming language. It is
a compiled language, but I still want to use Python as a reference.
Python has a lot of similarities to my language, such as indentation
for code blocks,

I hope you meant to say "*forced* indention for code blocks"! "Forced"
being the key word here. What about tabs over spaces, have you decided
the worth of one over the other or are you going to repeat Guido's
folly?

And please, i love Python, but the language is a bit asymmetrical. Do
try to bring some symmetry to this new language. You can learn a lot
from GvR's triumphs, however, you can learn even more from his follys.
 
R

Rick Johnson

I recommend demanding that indentation strictly alternate tabs or
spaces in successive non-blank lines.
Funny.

Comment-only lines must be
identical to the immediately-preceding line.

....as in "indentation" you mean, then yes. OR suffer the syntax error.
A tab is equivalent to
seven spaces.

....as for "the litmus test of stdlib code" you mean, then yes. OR
suffer the syntax error.
 
T

Travis Parks

I hope you meant to say "*forced* indention for code blocks"! "Forced"
being the key word here. What about tabs over spaces, have you decided
the worth of one over the other or are you going to repeat Guido's
folly?

And please, i love Python, but the language is a bit asymmetrical. Do
try to bring some symmetry to this new language. You can learn a lot
from GvR's triumphs, however, you can learn even more from his follys.

Personally, I find a lot of good things in Python. I thinking tabs are
out-of-date. Even the MAKE community wishes that the need for tabs
would go away and many implementations have done just that. I have
been seriously debating about whether to force a specific number of
spaces, such as the classic 4, but I am not sure yet. Some times, 2 or
even 8 spaces is appropriate (although I'm not sure when).

I have always found the standard library for Python to be disjoint.
That can be really beneficial where it keeps the learning curve down
and the size of the standard modules down. At the same time, it means
re-learning whenever you use a new module.

My language combines generators and collection initializers, instead
of creating a whole new syntax for comprehensions.

[| for i in 0..10: for j in 0.10: yield return i * j |]

Lambdas and functions are the same thing in my language, so no need
for a special keyword. I also distinguish between initialization and
assignment via the let keyword. Also, non-locals do not need to be
defined explicitly, since the scoping rules in Unit are far more
"anal".

In reality though, it takes a certain level of arrogance to assume
that any language will turn out without bumps. It is like I was told
in college long ago, "Only the smallest programs are bug free." I
think the same thing could be said for a language. The only language
without flaws would be so small that it would be useless.

I love these types of discussions though, because it helps me to be
aware. When designing a language, it is extremely helpful to hear what
language features have led to problems. For instance, C#'s foreach
loops internally reuse a variable, which translates to something like
this:

using (IEnumerator<T> enumerator = enumerable.GetEnumerator())
{
T current;
while (enumerator.MoveNext())
{
current = enumerator.Current;
// inner loop code goes here
}
}

Since the same variable is reused, threads referencing the loop
variable work against whatever value is currently in the variable,
rather than the value when the thread was created. Most of the time,
this means every thread works against the same value, which isn't the
expected outcome. Moving the variable inside the loop _may_ help, but
it would probably be optimized back out of the loop by the compiler.
With the growth of threaded applications, these types of stack-based
optimizations may come to an end. That is why it is important for a
next-gen language to have a smarter stack - one that is context
sensitive. In Unit, the stack grows and shrinks like a dynamic array,
at each scope, rather than at the beginning and end of each function.
Sure, there's a slight cost in performance, but a boost in
consistency. If a programmer really wants the performance, they can
move the variable out of the loop themselves.

In fact, there are a lot of features in Unit that will come with
overhead, such as default arguments, non-locals, function-objects,
etc. However, the game plan is to avoid the overhead if it isn't used.
Some things, such as exception handling, will be hard to provide
without overhead. My belief is that, provided a tool, most developers
will use it and accept the slight runtime overhead.

I think everyone has an idea about what would make for the perfect
language. I am always willing to entertain ideas. I have pulled from
many sources: C#, Java, Python, JavaScript, F#, Lisp and more. The
hope is to provide as much expression with as much consistency as
possible. Just the other day I spent 2 hours trying to determine how
to create a null pointer (yeah, it took that long).

let pi = null as shared * Integer32 # null is always a pointer

Originally, I wanted 'as' to be a safe conversion. However, I decided
to make use of the 'try' keyword to mean a safe conversion.

let nd = try base as shared * Derived
let d = if nd.Succeeded: nd.Value else: null
# or, shorthand
let i = try Integer32.Parse("123") else 0

Of course, the last line could cost performance wise. For that reason,
Unit will allow for "try" versions of methods.

let Parse = public static method (value: String)
throws(FormatException UnderflowException OverflowException)
returns(Integer32): ...
and Parse = public static try method (value: String)
returns(TryResult<Integer32>): ...

Of course, such methods are required to never throw and must return a
specific named tuple type.

Type, type, type. In short, I can only hope my language is useful and
that I dodge as many inconsistencies as possible. The good thing about
an unknown language is that no one gets mad when things change. In
that sense, Python's annoyances are probably an indication of its
quality. :)
 
C

Colin Higwell

I hope you meant to say "*forced* indention for code blocks"! "Forced"
being the key word here. What about tabs over spaces, have you decided
the worth of one over the other or are you going to repeat Guido's
folly?

And please, i love Python, but the language is a bit asymmetrical. Do
try to bring some symmetry to this new language. You can learn a lot
from GvR's triumphs, however, you can learn even more from his follys.

Personally, I find a lot of good things in Python. I thinking tabs are
out-of-date. Even the MAKE community wishes that the need for tabs would
go away and many implementations have done just that. I have been
seriously debating about whether to force a specific number of spaces,
such as the classic 4, but I am not sure yet. Some times, 2 or even 8
spaces is appropriate (although I'm not sure when).

I have always found the standard library for Python to be disjoint. That
can be really beneficial where it keeps the learning curve down and the
size of the standard modules down. At the same time, it means
re-learning whenever you use a new module.

My language combines generators and collection initializers, instead of
creating a whole new syntax for comprehensions.

[| for i in 0..10: for j in 0.10: yield return i * j |]

Lambdas and functions are the same thing in my language, so no need for
a special keyword. I also distinguish between initialization and
assignment via the let keyword. Also, non-locals do not need to be
defined explicitly, since the scoping rules in Unit are far more "anal".

In reality though, it takes a certain level of arrogance to assume that
any language will turn out without bumps. It is like I was told in
college long ago, "Only the smallest programs are bug free." I think the
same thing could be said for a language. The only language without flaws
would be so small that it would be useless.

I love these types of discussions though, because it helps me to be
aware. When designing a language, it is extremely helpful to hear what
language features have led to problems. For instance, C#'s foreach loops
internally reuse a variable, which translates to something like this:

using (IEnumerator<T> enumerator = enumerable.GetEnumerator())
{
T current;
while (enumerator.MoveNext())
{
current = enumerator.Current;
// inner loop code goes here
}
}

Since the same variable is reused, threads referencing the loop variable
work against whatever value is currently in the variable, rather than
the value when the thread was created. Most of the time, this means
every thread works against the same value, which isn't the expected
outcome. Moving the variable inside the loop _may_ help, but it would
probably be optimized back out of the loop by the compiler. With the
growth of threaded applications, these types of stack-based
optimizations may come to an end. That is why it is important for a
next-gen language to have a smarter stack - one that is context
sensitive. In Unit, the stack grows and shrinks like a dynamic array, at
each scope, rather than at the beginning and end of each function. Sure,
there's a slight cost in performance, but a boost in consistency. If a
programmer really wants the performance, they can move the variable out
of the loop themselves.

In fact, there are a lot of features in Unit that will come with
overhead, such as default arguments, non-locals, function-objects, etc.
However, the game plan is to avoid the overhead if it isn't used. Some
things, such as exception handling, will be hard to provide without
overhead. My belief is that, provided a tool, most developers will use
it and accept the slight runtime overhead.

I think everyone has an idea about what would make for the perfect
language. I am always willing to entertain ideas. I have pulled from
many sources: C#, Java, Python, JavaScript, F#, Lisp and more. The hope
is to provide as much expression with as much consistency as possible.
Just the other day I spent 2 hours trying to determine how to create a
null pointer (yeah, it took that long).

let pi = null as shared * Integer32 # null is always a pointer

Originally, I wanted 'as' to be a safe conversion. However, I decided to
make use of the 'try' keyword to mean a safe conversion.

let nd = try base as shared * Derived let d = if nd.Succeeded: nd.Value
else: null # or, shorthand let i = try Integer32.Parse("123") else 0

Of course, the last line could cost performance wise. For that reason,
Unit will allow for "try" versions of methods.

let Parse = public static method (value: String) throws(FormatException
UnderflowException OverflowException) returns(Integer32): ...
and Parse = public static try method (value: String)
returns(TryResult<Integer32>): ...

Of course, such methods are required to never throw and must return a
specific named tuple type.

Type, type, type. In short, I can only hope my language is useful and
that I dodge as many inconsistencies as possible. The good thing about
an unknown language is that no one gets mad when things change. In that
sense, Python's annoyances are probably an indication of its quality.
:)

Most of this is way above my head but FWIW, I am very happy with four
spaces for indentation. I forget now what I used in BASIC and COBOL, but
I have always used four spaces in PL/SQL, PL/pgSQL, PL/Tcl, c, ksh, bash
and Python.
 
S

Steven D'Aprano

Personally, I find a lot of good things in Python. I thinking tabs are
out-of-date. Even the MAKE community wishes that the need for tabs would
go away and many implementations have done just that.

Tabs have every theoretical advantage and only one practical
disadvantage: the common toolsets used by Unix programmers are crap in
their handling of tabs, and instead of fixing the toolsets, they blame
the tabs.

The use of spaces as indentation is a clear case of a technically worse
solution winning over a better solution.

I have been
seriously debating about whether to force a specific number of spaces,
such as the classic 4, but I am not sure yet. Some times, 2 or even 8
spaces is appropriate (although I'm not sure when).

Why on earth should your language dictate the width of an indentation? I
can understand that you might care that indents are consistent within a
single source code unit (a file?), but anything more than that is just
obnoxious.

I have always found the standard library for Python to be disjoint. That
can be really beneficial where it keeps the learning curve down and the
size of the standard modules down. At the same time, it means
re-learning whenever you use a new module.

I know what disjoint means, but I don't understand what you think it
means for a software library to be disjoint. I don't understand the rest
of the paragraph.

My language combines generators and collection initializers, instead of
creating a whole new syntax for comprehensions.

[| for i in 0..10: for j in 0.10: yield return i * j |]

Are we supposed to intuit what that means?

Is | a token, or are the delimiters [| and |] ?

Is there a difference between iterating over 0..10 and iterating over
what looks like a float 0.10?

What is "yield return"?

Lambdas and functions are the same thing in my language, so no need for
a special keyword.

That does not follow. Lambdas and def functions are the same thing in
Python, but Python requires a special keyword.

I also distinguish between initialization and
assignment via the let keyword.

What does this mean? I can guess, but I might guess wrong.

Also, non-locals do not need to be
defined explicitly, since the scoping rules in Unit are far more "anal".

What does this mean? I can't even guess what you consider more anal
scoping rules.

In reality though, it takes a certain level of arrogance to assume that
any language will turn out without bumps. It is like I was told in
college long ago, "Only the smallest programs are bug free." I think the
same thing could be said for a language. The only language without flaws
would be so small that it would be useless.

I'm pretty sure that being so small that it is useless would count as a
flaw.

What does it mean to say that a language is "small"?

A Turing Machine is a pretty small language, with only a few
instructions: step forward, step backwards, erase a cell, write a cell,
branch on the state of the cell. And yet anything that can be computed,
anything at all, can be computed by a Turning Machine: a Turing Machine
can do anything you can do in C, Lisp, Fortran, Python, Java... and very
probably anything you can (mentally) do, full stop. So what does that
mean about "small" languages?

On the other hand, take Epigram, a functional programming language:

http://en.wikipedia.org/wiki/Epigram_(programming_language)

It is *less* powerful than a Turing Machine, despite being far more
complex. Similarly languages like regular expressions, finite automata
and context-free grammers are more complex, "bigger", possibly with
dozens or hundreds of instructions, and yet less powerful. Likewise for
spreadsheets without cycles.

Forth is much smaller than Java, but I would say that Forth is much, much
more powerful in some sense than Java. You could write a Java compiler in
Forth more easily than you could write a Forth compiler in Java.
 
C

Chris Angelico

What does it mean to say that a language is "small"?

A Turing Machine is a pretty small language, with only a few
instructions: step forward, step backwards, erase a cell, write a cell,
branch on the state of the cell. And yet anything that can be computed,
anything at all, can be computed by a Turning Machine...

Ook has only three tokens (okay, it's a derivative of BrainF** so it
kinda has eight, but they're implemented on three). It's
Turing-complete, but it is so small as to be useless for any practical
purposes. The ONLY way to use Ook for any useful code would be to
write an interpreter for another language in it, and use that other
language.

However, Ook can be proven to be flawless, as can an Ook interpreter,
much more easily than a full-featured language like Python or C.

ChrisA
 
T

Travis Parks

Personally, I find a lot of good things in Python. I thinking tabs are
out-of-date. Even the MAKE community wishes that the need for tabs would
go away and many implementations have done just that.

Tabs have every theoretical advantage and only one practical
disadvantage: the common toolsets used by Unix programmers are crap in
their handling of tabs, and instead of fixing the toolsets, they blame
the tabs.

The use of spaces as indentation is a clear case of a technically worse
solution winning over a better solution.
I have been
seriously debating about whether to force a specific number of spaces,
such as the classic 4, but I am not sure yet. Some times, 2 or even 8
spaces is appropriate (although I'm not sure when).

Why on earth should your language dictate the width of an indentation? I
can understand that you might care that indents are consistent within a
single source code unit (a file?), but anything more than that is just
obnoxious.
I have always found the standard library for Python to be disjoint. That
can be really beneficial where it keeps the learning curve down and the
size of the standard modules down. At the same time, it means
re-learning whenever you use a new module.

I know what disjoint means, but I don't understand what you think it
means for a software library to be disjoint. I don't understand the rest
of the paragraph.
My language combines generators and collection initializers, instead of
creating a whole new syntax for comprehensions.
[| for i in 0..10: for j in 0.10: yield return i * j |]

Are we supposed to intuit what that means?

Is | a token, or are the delimiters [| and |] ?

Is there a difference between iterating over 0..10 and iterating over
what looks like a float 0.10?

What is "yield return"?
Lambdas and functions are the same thing in my language, so no need for
a special keyword.

That does not follow. Lambdas and def functions are the same thing in
Python, but Python requires a special keyword.
I also distinguish between initialization and
assignment via the let keyword.

What does this mean? I can guess, but I might guess wrong.
Also, non-locals do not need to be
defined explicitly, since the scoping rules in Unit are far more "anal"..

What does this mean? I can't even guess what you consider more anal
scoping rules.
In reality though, it takes a certain level of arrogance to assume that
any language will turn out without bumps. It is like I was told in
college long ago, "Only the smallest programs are bug free." I think the
same thing could be said for a language. The only language without flaws
would be so small that it would be useless.

I'm pretty sure that being so small that it is useless would count as a
flaw.

What does it mean to say that a language is "small"?

A Turing Machine is a pretty small language, with only a few
instructions: step forward, step backwards, erase a cell, write a cell,
branch on the state of the cell. And yet anything that can be computed,
anything at all, can be computed by a Turning Machine: a Turing Machine
can do anything you can do in C, Lisp, Fortran, Python, Java... and very
probably anything you can (mentally) do, full stop. So what does that
mean about "small" languages?

On the other hand, take Epigram, a functional programming language:

http://en.wikipedia.org/wiki/Epigram_(programming_language)

It is *less* powerful than a Turing Machine, despite being far more
complex. Similarly languages like regular expressions, finite automata
and context-free grammers are more complex, "bigger", possibly with
dozens or hundreds of instructions, and yet less powerful. Likewise for
spreadsheets without cycles.

Forth is much smaller than Java, but I would say that Forth is much, much
more powerful in some sense than Java. You could write a Java compiler in
Forth more easily than you could write a Forth compiler in Java.

Yes. I was mostly rambling. More explanation would have meant more
typing.

Languages that use type inference heavily typically find unique ways
of indicating literals, including numbers and collections. In Unit,
[||] indicates fixed length arrays, [] is for dynamic arrays, {} is
for sets and unordered dictionaries (at least one value is needed). A
frozen set might be represented with a {||} in the future. I stole the
syntax from F#. Numbers have a trailing letter indicating their types:
signed byte (y), short (s), long (l), float (f), fixed (m), arbitrary
precision (i), rational (r) and imaginary (j). Unsigned versions have
a u before the letter (uy).

Also, .. is the range operator in Unit. 0..10 means "0 through 10" and
0.1 means a floating point number (I missed a dot). 0..10..2 means 0,
2, 4, 6, 8, 10. Saves me from needing a range function, like Python.
Quite a few functional languages support that syntax.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top