Why Ring?
The language is simple, trying to be natural, encourage organization and comes with transparent and visual implementation. It comes with compact syntax and a group of features that enable the programmer to create natural interfaces and declarative domain-specific languages in a fraction of time. It is very small, flexible and comes with smart garbage collector that puts the memory under the programmer control. It supports many programming paradigms, comes with useful and practical libraries. The language is designed for productivity and developing high quality solutions that can scale.
Designed for a Clear Goal
- Applications programming language.
- Productivity and developing high quality solutions that can scale.
- Small and flexible language that can be embedded in C/C++ projects.
- Simple language that can be used in education and introducing Compiler/VM concepts.
- General-Purpose language that can be used for creating domain-specific libraries, frameworks and tools.
- Practical language designed for creating the next version of the Programming Without Coding Technology software.
Simple
Ring is a very simple language, and has a very straightforward syntax. It encourages programmers to program without boilerplate code.
To print something using the standard output, We can use the 'See' command.
The Main function is optional and will be executed after the statements, and is useful for using the local scope.
func main see "Hello, World!"
Uses Dynamic Typing and Lexical scoping.
Also we can use the '+' operator for string concatenation.
Trying to be natural
Ring is not case-sensitive
see "Enter your name ? " give name see "Hello " + Name # Name is the same as nameThe list index starts from 1
aList = ["one","two","three"] see aList[1] # print oneCall functions before definition
one() two() three() func one see "One" func two see "two" func three see "three"The assignment operator uses Deep copy (no references in this operation)
aList = ["one","two","three"] aList2 = aList aList[1] = 1 see alist[1] # print 1 see aList2[1] # print one
Pass numbers and strings by value, but pass lists and objects by reference.
The for in loop can update the list items.
Using Lists during definition
aList = [ [1,2,3,4,5] , aList[1] , aList[1] ] see aList # print 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5Exit from more than one loop
for x = 1 to 10 for y = 1 to 10 see "x=" + x + " y=" + y + nl if x = 3 and y = 5 exit 2 # exit from 2 loops ok next nextEncourage Organization
The language encourage organization, Forget bad days using languages where the programmer start with function then class then function and a strange mix between things!
Each source file follow the next structure
- Load Files
- Statements and Global Variables
- Functions
- Packages and Classes
This enable us to use Packages, Classes and Functions without the need to use a keyword to end these components.
We can write one line comments and multi-line comments
The comment starts with # or //
Multi-line comments are written between /* and */
Data Representation
Ring contains only four (4) types that represent the program data. These types are (String, Number, List & Object). The idea is to have many use cases for each type which increase the flexibility and the ability to write functions that are more usable in different situations.
The String type is used to represent:
- One character
- A string of many characters
- Multi-line string
- Binary Data
The Number type is used to represent
- Boolean Values
- Signed/Unsigned Integers
- Float/Double
The List type is used instead of
- One Dimension Arrays
- Multi-Dimension Arrays
- Lists of multiple types
- Nested Lists
- Hash Tables (Key & Value)
- Tree
- Wrapper around a C Pointer
The Object type is used to represent objects created from classes
Using classes and operator overloading we can create custom types
Compact Syntax
The language is not line sensitive, you don't need to write ; after statements, also you don't need to press ENTER or TAB, so we can write the next code
see "The First Message" see " Another message in the same line! " + nl see "Enter your name?" give Name see "Hello " + NameThe next code create a class called Point contains three attributes X,Y and Z. No keywords is used to end the package/class/function definition. Also, we can write the attributes names directly below the class name.
class Point X Y ZWe can use classes and functions before their definition, In this example we will create new object, set the object attributes then print the object values.
o1 = new point o1.x=10 o1.y=20 o1.z=30 see O1 class Point X Y ZInstead of using the dot '.' operator to access the object attributes and methods we can use braces { } to access the object, then we can use the object attributes and methods.
o1 = new point { x=10 y=20 z=30 } see O1 class Point X Y ZNow we will call a method after accessing the object using { }
oPerson = new Person { Name = "Somebody" Address = "Somewhere" Phone = "0000000" Print() # here we call the Print() method } class Person Name Address Phone func Print see "Name :" + name + nl + "Address :" + Address + nl + "Phone : " + phone + nlWhen we use { } to access the object then write any attribute name, the language will check the class for any setter/getter methods that will be called automatically.
new Number { see one # Execute GetOne() see two # Execute GetTwo() see three # Execute GetThree() } class Number one two three func GetOne see "Number : One" + nl return 1 func GetTwo see "Number : Two" + nl return 2 func GetThree see "Number : Three" + nl return 3Syntax Flexibility
Ring comes with many styles for writing your source code. Also, You can change the language keywords and operators and create your custom style!
- The First Style
def main put "Welcome to Ring! " + nl new test { start() } end class Test x = 10 y = 20 def start put "x+y=" + (x+y) + nl for t=1 to 10 put "t = " + t + nl if t=3 put "Three" + nl end end end end
load "stdlib.ring" func main() { print("Welcome to Ring! \n") new test { start() } } class Test { x = 10 y = 20 func start { print("x+y=" + (x+y) + "\n") for t=1 to 10 { print("t = " + t + " \n") if t=3 { print("Three \n") } } } }
ChangeRingKeyword See Print Print "Hello, World!" ChangeRingKeyword Print See See "Hello, World!" ChangeRingKeyword See Show Show "Hello, World!"
Define Natural Statements based on Object-Oriented
After the object access using { } if the class contains a method called BraceEnd() it will be executed!
TimeForFun = new journey # The first surprise! TimeForFun { Hello it is me # What a beautiful programming world! } # Our Class class journey hello it is me func GetHello ? "Hello" func braceEnd ? "Goodbye!"We can execute code written in strings using the Eval() function
cCode = "See 'Code that will be executed later!' " Eval(cCode) # execute the code to print the messageWe can create a list then execute code generated from that list
aWords = ["hello","it","is","me"] for word in aWords cCode=word+"=0" eval(cCode) nextWe can read text files using the Read(cFileName) function and we can write files using the Write(cFileName,cString) function.
see "Enter File Name:" give cFileName see read(cFileName) # Print the file content
The next example presents how to create a class that defines two instructions
The first instruction is : I want window
The second instruction is : Window title = Expression
Also keywords that can be ignored like the **the** keyword
To complete the previous example, use read() to get the content of a file that contains
I want window The window title = "hello world"
Then use eval() to execute the content of that file!.
Also, you can update the methods GetWindow() and SetTitle() to create Real windows using the GUI Library
Define Declarative Languages using Nested Structures based on Object-Oriented
We learned how to use Natural statements to execute our code and using the same features we can use nested structures to execute our code.
The next example from the Web library, generate HTML document using the Bootstrap library.
No HTML code is written directly in this example, we created a similar language (just as example)
Then using this declarative language that uses nested structures, we generated the HTML Document..
The idea in this example is that the GetDiv() and GetH1() methods return an object that we can
access using {} and after each object access the method BraceEnd() will be executed to send the
generated HTML to the parent object until we reach to the root where BraceEnd() will print the output.
The classes that power the declarative interface looks like this
class Link from ObjsBase title link func braceend cOutput = nl+GetTabs() + " "+ Title + " " + nl class Div from ObjsBase func braceend cOutput += nl+'" + nl cOutput = TabMLString(cOutput)