Introduction
In 2010, I developed a new programming language called Supernova. This language uses a code that looks similar to Natural Language statements to create simple GUI applications. After five years, in the Ring programming language, we can get similar results, but now we have the ability to create/use code similar to Natural language statements in any domain that we like or need.
The Ring programming language comes with the Supernova sprite, but with more generalization and with a mix of other languages sprites.
The language comes with better support for Natural Language Programming and Declarative Programming. The innovation comes in supporting these paradigms with new practical techniques on the top of Object-Oriented Programming and Functional Programming. Ring provides programmers with the tools required to build a Natural Language like Supernova or Declarative Language like REBOL and QML without the need to know anything about (Compilers and Parsing). You get the language constructs ready for use to create domain-specific languages in a fraction of time.
Using the Ring programming language, we can create Natural programming languages based on classes and objects.
In Supernova language, we can type (I want window and the window title is hello world.) and it will create a GUI window with “Hello, World!
” as the window title. When I created Supernova language in 2010, I discovered that using the Natural Code can be like English without limits and we can get the human language power in programming, but to implement that, we need a new language that is:
- General Purpose
- Practical
- Can create Natural Languages very quickly
So we can get a System that can increase ease of use and productivity to the maximum level.
Supernova was just a test for the idea. To get a near view about what are the advantages and disadvantages. After testing the new ideas, you provide something practical. So we have the Ring language after the Supernova language.
Why the Ability to Define Your Own Languages Instead of Just Handing Over the Syntax So You Can Parse It Using Whatever Code You Like?
It’s innovation - You create natural statements without the need to learn about parsing. You just use Classes which is an intelligent decision (where later we can mix between classes to support more statements based on the context - we can change and translate the defined statements and many more!). Also, the statements are added in Ring World where you can use any Ring statement.
Why Natural Language Programming, We Can Do Anything Using Imperative, Object-Oriented and Functional Languages?
When you design a new language, you can learn from the past but you must look forward and live in the Future. What you know about Natural Programming maybe based on the Old Knowledge about the power of these paradigms in the practical world and I agree with you but I see another technique that can be applied to get this to work practically. What you miss about Natural Languages is that they are Context Sensitive and this means we can use it and think different about how we can express our ideas.
Example (1): I want a window that contains 3 buttons.
In one sentence, I created 4 objects (the window and the three buttons) and added the buttons to the window. The idea of Natural Programming is to get many things done like that.
Example (2): Accept 2 numbers, then print the sum.
Background
You can check this article about the Supernova programming language and this article about the Ring programming language.
Also check the next Tutorials about the Ring programming language.
- Getting Started
- Control Structures
- Functions
- Lists
- Classes
Features in Ring Language That Help in Supporting Natural Language
(1) Compact Syntax, No explicit end for statements (No ; or ENTER is required)
Example:
See "What is your name? " give cName see "Hello " + cName
Or in another style:
Put "What is your name? " Get cName Put "Hello " + cName
(2) Using braces { }, we can access objects and use the attributes/methods directly as variables/functions:
Example:
New point # create new object using the point class
{ # access the new object attributes and methods
x = 10 # set the x attribute to 10
y = 20 # set the y attribute to 20
z = 30 # set the z attribute to 30
print() # call the print method
} # end of object access
Class Point # define the Point class
x y z # the class contains three attributes x, y & z
func print # define the print method
see x + nl + # print the x attribute
y + nl + # print the y attribute
z + nl # print the z attribute
(3) We can define methods to be used when we set and get object attributes.
Example:
o1 = new person
o1.name = "Mahmoud" see o1.name + nl
o1 { name = "Ahmed" see name }
Class Person
name family = "Fayed"
func setname value
see "Message from SetName() Function!" + nl
name = value + " " + family
func getname
see "Message from GetName() Function!" + nl
return "Mr. " + name
Output:
Message from SetName() Function!
Message from GetName() Function!
Mr. Mahmoud Fayed
Message from SetName() Function!
Message from GetName() Function!
Mr. Ahmed Fayed
Using the code
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 = <expr>
Also keywords that can be ignored like the ‘the
’ keyword
New App
{
I want window
The window title = "hello world"
}
Class App
# Attributes for the instruction I want window
i want window
nIwantwindow = 0
# Attributes for the instruction Window title
# Here we don't define the window attribute again
title
nWindowTitle = 0
# Keywords to ignore, just give them any value
the=0
func geti
if nIwantwindow = 0
nIwantwindow++
ok
func getwant
if nIwantwindow = 1
nIwantwindow++
ok
func getwindow
if nIwantwindow = 2
nIwantwindow= 0
see "Instruction : I want window" + nl
ok
if nWindowTitle = 0
nWindowTitle++
ok
func settitle cValue
if nWindowTitle = 1
nWindowTitle=0
see "Instruction : Window Title = " + cValue + nl
ok
Output:
Instruction : I want window
Instruction : Window Title = hello world
What if we want to connect between the two instructions using ‘and
’:
We have a problem because in Ring ‘and
’ is a keyword.
We can change that using the ChangeRingKeyword
command.
The ChangeRingKeyword
command is executed in the scanner stage by the compiler (before parsing).
Note: Remember to restore the keyword again.
Syntax:
ChangeRingKeyword <oldkeyword> <newkeyword>
Example:
ChangeRingKeyword and _and
New App
{
I want window and the window title = "hello world"
}
Class App
# Attributes for the instruction I want window
i want window
nIwantwindow = 0
# Attributes for the instruction Window title
# Here we don't define the window attribute again
title
nWindowTitle = 0
# Keywords to ignore, just give them any value
the=0 and=0
ChangeRingKeyword _and and
func geti
if nIwantwindow = 0
nIwantwindow++
ok
func getwant
if nIwantwindow = 1
nIwantwindow++
ok
func getwindow
if nIwantwindow = 2
nIwantwindow= 0
see "Instruction : I want window" + nl
ok
if nWindowTitle = 0
nWindowTitle++
ok
func settitle cValue
if nWindowTitle = 1
nWindowTitle=0
see "Instruction : Window Title = " + cValue + nl
ok
func getand
see "Using : and" + nl
Output:
Instruction : I want window
Using : and
Instruction : Window Title = hello world
What if we want to define a new behavior for any operator like the “=
” operator.
We can do this change using the ChangeRingOperator
command to hide operator (change its name).
Then we can use the operator as identifier that we can handle its behaviour.
Syntax:
ChangeRingOperator <oldoperator> <newoperator>
Now we will change the ‘=
’ operator to ‘is
’.
Example:
ChangeRingKeyword and _and
ChangeRingOperator = is
New App
{
I want window and the window title is "hello world"
}
ChangeRingOperator is =
Class App
# Attributes for the instruction I want window
i want window
nIwantwindow = 0
# Attributes for the instruction Window title
# Here we don't define the window attribute again
title
nWindowTitle = 0
# Keywords to ignore, just give them any value
the=0 and=0
ChangeRingKeyword _and and
func geti
if nIwantwindow = 0
nIwantwindow++
ok
func getwant
if nIwantwindow = 1
nIwantwindow++
ok
func getwindow
if nIwantwindow = 2
nIwantwindow= 0
see "Instruction : I want window" + nl
ok
if nWindowTitle = 0
nWindowTitle++
ok
func settitle cValue
if nWindowTitle = 1
nWindowTitle=0
see "Instruction : Window Title = " + cValue + nl
ok
Eval() Function
We can execute code during runtime from string
using the Eval()
function.
Syntax:
Eval(cCode)
Example:
Eval("nOutput = 5+2*5 " )
See "5+2*5 = " + nOutput + nl
Eval("for x = 1 to 10 see x + nl next")
Eval("func test see 'message from test!' ")
test()
Output:
5+2*5 = 15
1
2
3
4
5
6
7
8
9
10
message from test!
Using Eval()
with our Natural Code:
func Main
cProgram = ' I want window and the window title is "hello world" '
MyLanguage(cProgram)
Func MyLanguage cCode
# We add to the code the instructions that change keywords and operators
# Because Eval() uses a new Compiler Object (the original keywords and operatos).
cCode = '
ChangeRingKeyword and _and
ChangeRingOperator = is
' + cCode
New App
{
eval(cCode)
}
Class App
# Attributes for the instruction I want window
i want window
nIwantwindow = 0
# Attributes for the instruction Window title
# Here we don't define the window attribute again
title
nWindowTitle = 0
# Keywords to ignore, just give them any value
the=0
ChangeRingKeyword and _and
and=0
ChangeRingKeyword _and and
func geti
if nIwantwindow = 0
nIwantwindow++
ok
func getwant
if nIwantwindow = 1
nIwantwindow++
ok
func getwindow
if nIwantwindow = 2
nIwantwindow= 0
see "Instruction : I want window" + nl
ok
if nWindowTitle = 0
nWindowTitle++
ok
func settitle cValue
if nWindowTitle = 1
nWindowTitle=0
see "Instruction : Window Title = " + cValue + nl
ok
BraceStart() and BraceEnd()
We can write code that will be executed before/after using { }
:
Example:
o1 = new test {
see "Hello" + nl
}
o1 {}
class test
func bracestart
see "start" + nl
func braceend
see "end" + nl
Output:
start
Hello
end
start
end
Using BraceExprEval()
The next example demonstrates how to use the “BraceExprEval
” method to get expressions in Natural code.
Example:
new natural {
create 5
}
class natural
create=0
lkeyword = false
func braceexpreval r
if lkeyword lkeyword=false return ok
see "expr eval" + nl
see "type: " + type(r) see nl
see "value : " see r see nl
func getcreate
lkeyword = true
see "create" + nl
Output:
create
expr eval
type: NUMBER
value : 5
Real Natural Code
The next example is a more advanced example.
# Natural Code
new program {
Accept 2 numbers then print the sum
}
# Natural Code Implementation
class program
# Keywords
Accept=0 numbers=0 then=0 print=0 the=0 sum=0
# Execution
func braceexpreval x
value = x
func getnumbers
for x=1 to value
see "Enter Number ("+x+") :" give nNumber
aNumbers + nNumber
next
func getsum
nSUm = 0
for x in aNumbers nSum+= x next
see "The Sum : " + nSum
private
value=0 aNumbers=[]
Output:
Enter Number (1) :3
Enter Number (2) :4
The Sum : 7
Using BraceError()
The next examples demonstrates how to use the “BraceError
” method to handle errors when accessing the object using braces {}
.
Example:
func main
o1 = new point {
x=10 y=20 z=30
TEST
SEE test
}
class point x y z
func braceerror
see "Handle Error!" + nl
SEE "Message :" + cCatchError + nl
if ( left(cCatchError,11) = "Error (R24)" ) and not isattribute(self,"test")
see "add attribute" + nl
addattribute(self,"test")
test = 10
ok
see "done" + nl
return
Output:
Handle Error!
Message :Error (R24) : Using uninitialized variable : test
add attribute
done
10
Example:
new point {
x=10 y=20 z=30
test()
see "mmm..." + NL
}
class point x y z
func braceerror
see "Handle Error!" + nl
see "Message :" + cCatchError + nl
see self
see "Done" + NL
Output:
Handle Error!
Message :Error (R3) : Calling Function without definition !: test
x: 10.000000
y: 20.000000
z: 30.000000
Done
mmm...
Clean Natural Code
Instead of typing the literal as “literal
”, we can accept the words directly.
Example:
The next example accepts hello world instead of “hello world
”:
ChangeRingKeyword and _and
ChangeRingOperator = is
New App
{
I want window and the window title is hello world
}
ChangeRingOperator is =
Class App
# Attributes for the instruction I want window
i want window
nIwantwindow = 0
# Attributes for the instruction Window title
# Here we don't define the window attribute again
title
nWindowTitle = 0
# Keywords to ignore, just give them any value
the=0 and=0
# Data
literal = ""
ChangeRingKeyword _and and
func geti
if nIwantwindow = 0
nIwantwindow++
ok
func getwant
if nIwantwindow = 1
nIwantwindow++
ok
func getwindow
if nIwantwindow = 2
nIwantwindow= 0
see "Instruction : I want window" + nl
ok
if nWindowTitle = 0
nWindowTitle++
ok
func settitle cValue
if nWindowTitle = 1
nWindowTitle=2
ok
func braceend
if nWindowTitle = 2
see "Instruction : Window Title = " + literal + nl
nWindowTitle = 0
ok
func braceerror
c= substr(cCatchError,":")
while c > 0
c= substr(cCatchError,":")
cCatchError=substr(cCatchError,c+1)
end
literal += substr(cCatchError,1)
Points of Interest
In 2010, I developed the Supernova language in 9 months. Now using Ring, I can implement a language like Supernova in a few days. The ability to define natural languages based on classes instead of creating a compiler is a big deal. This increases the productivity and decreases the complexity of the problem. You can create large natural programming language and still control the project. Think of implementing your next natural programming language using Ring!
History
- 13th October, 2016: Initial version
There is a lot of work done in Natural Programming Languages. The Ring programming language is a practical programming language that tries to push Natural Language Programming a step forward. Ring is a new language released on 2016.01.25.