Click here to Skip to main content
13,800,416 members
Click here to Skip to main content
Add your own
alternative version

Stats

4.8K views
27 downloads
2 bookmarked
Posted 21 Dec 2017
Licenced CPOL

The declarative approach of the Ring programming language

, 22 Dec 2017
Rate this:
Please Sign up or sign in to vote.
We will learn about the innovation in the declarative approach of the Ring programming language.

Download sample

Introduction

When we look at some popular declarative programming languages like QML, REBOL and Red, we will discover that using nested structures of objects to describe the solution is a practical way to solve some real problems where we can focus on the objects, properties and how these objects are related together. A lot of domain specific languages can be developed using the same programming paradigm, but developing a domain specific programming language need some time, tools and skills to be done right! and the language limitations could lead to problems in the future where the language extension may requires advanced skills.

Towards solving this problem, which is already solved many years ago, a lot of popular general-purpose programming languages, provided some ways to develop domain specific languages. A notable and modern  language in this area is the Ruby programming language. Ruby comes with nice features like beatiful syntax, blocks and meta-programming where using these features a lot of domain specific languages are developed and used in practice. Also the Kotlin programming language played a role in this area and provided nice features to achive this goal. Sure a lot of programming languages did that, But Ruby and Kotlin are what comes to my mind for now.

When I designed the Ring programming language, I was aware about this problem, the different successfull solutions that are developed, But having a problem that can be solved in different ways doesn't prevent us from providing new solution that maybe more useful and better in some way at least in our opinion as a start.

In this article I will present the innovative features in the Ring programming language that can be used to develop domain-specific declarative programming languages using nested structure. I will show the big picture and how the ideas can be reused to develop any domain specific language that we need.

Background

It would be nice if you can look at the next examples in QML, REBOL, Ruby and Kotlin to know how the declarative code may look like. These examples are already public and can be shared, I'm just using them here in the begining to give you some practical idea about how things looks in the declarative apporach using nested structures.

(1) QML Example

import QtQuick 2.9 #import from Qt 5.9

 Rectangle {
     id: canvas
     width: 250
     height: 200
     color: "blue"

     Image {
         id: logo
         source: "pics/logo.png"
         anchors.centerIn: parent
         x: canvas.height / 5
     }
 }

(2) REBOL Example

view [text "Hello world!" button "Quit" on-action [quit]]

The advantage of this approach is that we can know the relationship between objects, define objects with/without names, set the objects attributes, and concentrate on our description (what we want to do)

Sure, This approach is not suitable for all problems, but it can be used in many useful cases.

I talked about using a general purpose language like Ruby to do something similar to that.

(3) The Ruby code may looks like this

output = FancyMarkup.new.document do
  body do
    div id: "container" do
      ul class: "pretty" do
        li "Item 1", class: :active
        li "Item 2"
      end
    end
  end
end

Or

output = FancyMarkup.new.document {
  body {
    div id: "container" {
      ul class: "pretty" {
        li "Item 1", class: :active
        li "Item 2"
      }
    }
  }
}

So the Ruby way is to use methods, blocks and it's beautiful syntax.

(4) The Kotlin code may looks like this

val data = mapOf(1 to "one", 2 to "two")

createHTML().table {
    for ((num, string) in data) {
        tr {
           td { +"$num" }
           td { +string }
        }
    }
}

The advantages of using a general-purpose language like Ruby or Kotlin to build a domain specific language could be getting more power (Extensions, Customization and Flexibilty) but this may lead to some complexity or at least a syntax  not so clean as we may find in pure domain specific languages.

Using the code

In the Ring programming language we provided an innovative approach to provide declarative programming using nested structures but with very clean syntax and advanced level of customization and flexibilty.

The basic idea of the declarative apporach in the Ring programming language : "Instead of using methods and passing parameters like blocks, anonymous functions or closures. We will just access the object at the client|caller side but using more beatuiful syntax based on using braces instead of the dot operator, where at the caller side we have more flexibility to access any object without modifying it's design (Class) and we can execute our code in the object context and use the public methods and attributes provided by that object. Also we have our local scope. We get the power that looks like closures (In this use case only) but in a more faster and simple implementation that doesn't include passing parameters or altering the methods definition. We just modify our classes to define only the methods that we will use to create new objects and set the relationships between these objects".

To understand how this idea is very useful, and to know why it's not used before Ring!

You have to remember an important thing about the real concept of the Object-Oriented Programming paradigm.

" I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages ", Prof. Alan Kay

And since both of Ruby and Kotlin are Object-Oriented languages, their designers are used to apply the paradigm concepts and hide the data (In most cases) and provide communication between system components using method calls. So block, anonymous functions, or closures comes to their mind when they tried to create domain specific languages based on their general purpose languages. Also the idea of passing functions as parameters is more related to functional programming and first-class functions and these languages take this paradigm too in mind. Sure I'm not talking about how they are thinking, I'm just talking about what I see from Ruby and Kotlin design at the practical side.

The Ring language take in mind these paradigms (Object-Oriented, Functional, etc) but when we implement a domain specific language, we look at the problem using a different point of view.

In Ring we decided that

(1) All attributes are public by default (This break a secuirty rule: principle of least privilege - for flexibility)

(2) You can create private attributes and methods if you want (for safety)

(3) If you have public attributes, You still have the option to create setter and getter methods (safety after flexibility)

(4) When you call a method that return an object, You can use braces to access that object directly

(5) You don't have to call a method directly, You can try to access an attribute, This will call the getter method that may return the object that you may access. This method will set the relationship between the new object and the current object (Parent)

Using these simple rules/concepts in the Ring programming language, We can go ahead and create a domain-specific language using nested strucutres.

Now, How this domain specific language will looks like?

Example (1) in Ring programming language

The next example uses a domain-specific language defined by the web library to create HTML pages

tags like div, h1, P, etc are just attributes. When we try to access these attributes the getter() method for each attribute will be called (getdiv(), geth1(), getp(), etc). These methods will create the object, Add it to the current object container (list) then return a reference to that object. Using braces { } we can access that object and we can set the new object attributes and call the object methods.

load "weblib.ring"
import System.Web

func Main

  BootStrapWebPage()
  {
        div
        {
          classname = :container
          div
          {
                classname = :jumbotron
                H1 {   text("Bootstrap Page")   }
          }
          div
          {
                classname = :row
                for x = 1 to 3
                  div
                  {
                        classname = "col-sm-4"
                        H3 { html("Welcome to the Ring programming language") }
                        P  { html("Using a scripting language is very fun!") }
                  }
                next
          }
        }
  }
 

Example (2) in Ring programming language

The next example from the 2D Game Engine that comes with the Ring language

   oGame {
                title = "Stars Fighter!"
                sprite
                {
                  file = "images/menu1.jpg"
                  x = 0 y=0 width=800 height = 600 scaled = true animate = false
                  keypress = func ogame,oself,nKey {
                        if nkey = key_esc or nKey = GE_AC_BACK
                          ogame.shutdown()
                        but nKey = key_space
                          oGameState.startplay=true
                          ogame.shutdown=true
                        ok
                  }
                  mouse = func ogame,oself,nType,aMouseList {
                        if nType = GE_MOUSE_UP
                          oGameState.startplay=true
                          ogame.shutdown=true
                        ok
                  }
                }
                text {
                  animate = false
                  size = 35
                  file = "fonts/pirulen.ttf"
                  text = "Stars Fighter"
                  x = 10  y=50
                }
                text {
                  animate = false
                  size = 25
                  file = "fonts/pirulen.ttf"
                  text = "Version 1.0"
                  x = 80  y=100
                }
                text {
                  animate = false
                  size = 16
                  file = "fonts/pirulen.ttf"
                  text = "(C) 2017, Mahmoud Fayed"
                  x = 45  y=140
                }

                text {
                  animate = false
                  size = 25
                  file = "fonts/pirulen.ttf"
                  text = "Press Space to start"
                  x = 190  y=470
                }
                text {
                  animate = false
                  size = 20
                  file = "fonts/pirulen.ttf"
                  text = "Press Esc to Exit"
                  x = 260  y=510
                }
                Sound {
                  file = "sound/music1.wav"
                }
          }
 

To learn more about the implementation : Check this chapter in Ring documentation

The next example explains the concept - Just read the comments to get an idea about how things are implemented.

#=============================================================================================
# Declarative Programming using nested structures
#=============================================================================================

new Container 				    # Create an object from the Container class 
{ 
	Point 				        # Try to use the Point attribute, This will call getPoint() 
	{    				        # Access the new object created by getPoint() method 
		x=10 y=20 z=30        	# Set the Object Attributes (x,y and z) 
	}                           # This will call the braceend() method 
}

#=============================================================================================
# Implementation using Classes
#=============================================================================================

Class Container                  # Our class that will contains many objects
	
	aObjs = []                   # A list to store the new objects (for example Points)
	
	point                        # An attribute 
	
	func getpoint                # A method to be called when we use the Point attribute  
	
		aObjs + new Point        # Create new object from the Point class, Add it to the list 
		return aObjs[len(aObjs)] # Return the new object 

Class Point x y z                # Define new class called Point 

     # A method to be called after accessing the object using braces
     
	 func braceend          
	 
	 	? "3D Point" + nl + x +   
	 	  nl + y + nl + z + nl 

Points of Interest

Using braces to access objects instead of the dot operator provided a different way to interact with objects and see more techniques to support declarative programming and natural programming.

In this article we talked about using this feature to develop domain specific languages using nested structures

In another articles I talked about using this feature for natural language programming

It's common to listen to developers saying that "Ruby blocks is one of the killer features in the language!"

Also in the Ring community "Ring braces is one of the killer features in the language!"

Ring is an innovative programming language that 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.

Also Ring is influenced by the next programming languages

  • Lua
  • Python
  • Ruby
  • C
  • C#
  • BASIC
  • QML
  • xBase
  • Supernova

History

The Ring is an innovative and practical general-purpose multi-paradigm language:

  • In November 2011, the idea of the new language was conceived
  • In Sept. 2013, the design and the implementation of the Ring programming language is started
  • In April 2015, the language name is selected
  • In May 2015, the Compiler was implemented
  • In Sept. 2015, the Documentation was done
  • In January 2016, the Ring 1.0 was released
  • In October 2016, the Ring 1.1 was released
  • In January 25, 2017, the Ring 1.2 was released
  • In May 15, 2017, the Ring 1.3 was released
  • In June 29, 2017, the Ring 1.4 was released
  • In August 21, 2017, the Ring 1.5 was released
  • In November 30, 2017, the Ring 1.6 was released

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

No Biography provided

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web02 | 2.8.181214.1 | Last Updated 22 Dec 2017
Article Copyright 2017 by Mahmoud Samir Fayed
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid