Dynamic Programming Language

peruvianwageslaveInternet και Εφαρμογές Web

5 Φεβ 2013 (πριν από 4 χρόνια και 6 μήνες)

160 εμφανίσεις


Write more understandable code in less lines


Free (Very open license)


Extensible


Dynamic languages such as Ruby can be very
productive in specific areas, such as
prototyping, web development or for gluing
various applications together.



Dynamic programming languages are often
referred to as 'weakly typed' which means
that variables are not bound to a particular
type until runtime.


It typically features "dynamic typing," which
gives the programmer more freedom to pass
parameters at runtime without having to
define them beforehand.


This dynamic typing is accomplished by using
an interpreted language, rather than a
compiled language.



A
scripting language
is a programming language
that allows control of one or more software
applications. "Scripts" are distinct from the core
code of the application, which is usually written in
a different language, and are often created or at
least modified by the end
-
user.

Scripts are often
interpreted from source code whereas the
applications they control are traditionally
compiled.


The name "script" is derived from the written
script of the performing arts, in which dialogue is
set down to be spoken by human actors.


interpreted (no linking or compilation)


less efficient to run


faster to develop (factor of 5 to 10)


high level


a single statement is more powerful


no type declarations,
typeless


powerful built
-
in types


can generate and interpret source code at run time
(via
eval
)


interface to underlying operating system


can call
operating system commands


plays well with others


glue

systems together


rarely used for complex algorithms or data
structures.


Examples:
javascript
,
perl
,
php
,
smalltalk
, ruby,
vbscript
, groovy,
emacslisp
,
awk
, python,
tcl
,
unix

shell.

Japanese Design Aesthetics Shine Through


Focus on human factors

`
Principle of Least
Surprise
:
when two
elements of an interface conflict, or are
ambiguous, the behavior should be that
which will least surprise the human user or
programmer at the time the conflict arises.



Principle of
Succinctness

The
supreme design goal of Ruby

Makes programmers happy and makes Ruby easy to learn

Examples


What class
does an object belong to ?


can ask

o.class

(returns the class object)


Is it
Array#size

or
Array#length
?

Either one
-

same
method


they’re
aliased


Is this good or bad design?


Array operators?


if it makes sense, they are defined.

diff = ary1


ary2 (removes elements of ary2 from ary1)

union = ary1 +
ary2 (concatenate arrays)


intersection = ary1 & ary2 (elements common to both)



also known as the
Principle
of Least
Effort

Motivation…


We don’t like to waste time


The
quicker we program, the more we
accomplish

Sounds reasonable enough, right?


Less code means less
bugs


Common needs are built
-
in.

All classes derived from
Object i
ncluding
Class
(like
Java) but there are no primitives (not like Java at
all
). EVERYTHING is an Object.


Ruby uses
single
-
inheritance


What are the dangers of multiple inheritance?


Mixins

give you the power of multiple inheritance

without the headaches


Modules allow addition of behaviors to a class


Reflection is built in along with lots of other highly
dynamic metadata features


Things like ‘=‘ and ‘+’ that you might think are
operators are actually methods (like Smalltalk)


a
mixin

is a class that is mixed with a
module. In other words the implementation
of the class and module are joined,
intertwined, combined, etc.


a module as a degenerate abstract class. A
module can’t be instantiated and no class can
directly extend it but a module can fully
implement methods.

# Convert a integer value to English.

02.module
Stringify

03.

# Requires an instance variable
@value

04.

def
stringify

05.

if @value == 1

06.

"One"

07.

elsif

@value == 2

08.

"Two"

09.

elsif

@value == 3

10.

"Three"

11.

end

12.

end

13.end



Stringify

makes use
of a @value instance
variable.


The class that will be
mixed with this
module needs to
define and set a
@value instance
variable


a module could
invoke methods
defined not in the
module itself but in the
class that it will be
mixed with.


# A Math module akin to Java Math class.

2.module Math

3.

# Could be called as a class, static, method

4.

def add(
val_one
,
val_two
)

5.

BigInteger.new
(
val_one

+
val_two
)

6.

end

7.end


# Base Number class

02.class Number

03.

def
intValue

04.

@value

05.

end

06.end

07.


08.#
BigInteger

extends Number

09.class
BigInteger

< Number

10.


11.

# Add instance methods from
Stringify

12.

include
Stringify

// mix methods at the instance level

13.


14.

# Add class methods from Math

15.

extend Math // mix methods at the class level

16.


17.

# Add a constructor with one parameter

18.

def initialize(value)

19.

@value = value

20.

end

21.end


# Call class method extended from Math

bigint2 =
BigInteger.add
(
-
2, 4)

puts bigint2.intValue


#
--
> 2


# Call a method included from
Stringify

puts bigint2.stringify


#
--
> 'Two'


# Format a numeric value as a currency


module
CurrencyFormatter



def format



"$#{@value}"



end


end

# Add the module methods to.# this object
instance, only!

bigint2.extend (
CurrencyFormatter
)

puts bigint2.format


#
--
> '$2'



Method
Chaining


applies methods from left to right

print
array.uniq.sort.reverse


Method Names include ! and ?

ary.sort
!


? returns a true or false


examples: defined? equal?


! changes the object that calls the method
(do it here!)


Iterators

and Blocks vs. Loops

files.each

{ |file| process(file) }


Case usage:


Class names begin with a Capital letter


Constants are ALL_CAPS


Everything else
-

method call or a local variable


Convention in naming:
Under_score

instead of
camelCase

0.upto(9)

do

|x|



print

x,

"

"

end

Produces: 0 1 2 3 4 5 6 7 8 9


[

1,

1,

2,

3,

5

].each

{|
val
|

print

val
,

"

"

}

Produces: 1 1 2 3 5


songList.each

do

|
aSong
|



aSong.play


end


Duck Typing

Based on signatures, not class
inheritance


In Ruby, we rely less on the type (or class) of an object and
more on its capabilities.


Duck Typing is a type of dynamic typing in which the object’s
current set of methods and properties determines the valid
semantics, rather than its inheritance from a particular class
or implementation of a specific interface.


The name of the concept refers to the duck test, attributed to
James Whitcomb Riley which may be phrased as follows:

"when I see a bird that walks like a duck and swims like a duck
and quacks like a duck, I call that bird a duck."



#

Check

whether

the

object

defines

the

to_str

method


puts

('A

string'.respond_to
?

:
to_str
)

#

=>

true


puts

(
Exception.new.respond_to
?

:
to_str
)

#

=>

true


puts

(4.respond_to?

:
to_str
)

#

=>

false



The above example is the simplest example of Ruby's
philosophy of "duck typing:" if an object quacks like a
duck (or acts like a string), just go ahead and treat it
as a duck (or a string). Whenever possible, you should
treat objects according to the methods they define
rather than the classes from which they inherit or the
modules they include.


class Duck


def quack


'Quack!'


end




def swim


'Paddle
paddle

paddle
...'


end


end




class Goose


def honk


'Honk!'


end


def swim


'Splash
splash

splash
...'


end


end




class
DuckRecording



def quack


play


end




def play


'Quack!'


end


end


If you are calling
“quack”, Duck and
DuckRecording

are
interchangeable


If you are calling
“swim”, Duck and
Goose are
interchangeable.


Method isn’t
expecting a specific
type JUST one with
the needed
functionality.


Dynamic
Dispatch

A key concept of OOP: methods are actually messages that
are
sent
to an object
instance


It is a runtime decision to decide which code to execute


Can’t be determined statically (method could have been
overridden dynamically)

foobar

=
Array
.new


foobar.class

#
=> Array

foobar.size

#
=> 0


Conceptually: First we search for “size” in Array. If it isn’t there, we look to
Object to define size. If the method isn’t found at the top of the
hierarchy, we have a “
method_missing
” message.




The new search path


foobar

=
Array
.new


def

foobar.size

// Adds a size method ONLY for the instance


“Infinity and beyond" ;

end



Languages with weak or no typing
systems often carry a dispatch table as
part of the object data for each object.
This allows
instance behavior

as each
instance may map a given message to a
separate method.


Languages with strong (static) typing use
a virtual table which defines method to
code mapping. Instances of the type
store a pointer to this table.




Suppose a program contains several classes in
an inheritance hierarchy: a
superclass

Cat, and
two subclasses,
HouseCat

and Lion. Class Cat
defines a virtual function named speak, so its
subclasses may provide an appropriate
implementation (e.g. either meow or roar).


When a Cat variable calls speak, we need to be
able to tell which method to call.


dispatch table contains addresses of methods


Use same layout for type
-
compatible methods


so we look for address at a constant offset




Dynamic Behavior


Reflection


Scope Reopening (Kind of like AOP)


Eval


Breakpoint debugger


One of the many advantages of dynamic
languages such as Ruby is the ability to
introspect
---
to examine aspects of the
program from within the program itself.
Some call this feature
reflection.


We might discover:


what objects it contains,


the current class hierarchy,


the contents and behaviors of objects, and


information on methods.



Everything is an object EVEN the class.


5.
class

#=>
Fixnum



"
hello".
class

#=> String


class

Foo


end


Foo.
class

#=> Class


Foo

is a constant known to the system as a
class



Have you ever craved the ability to traverse
all

the living objects
in your program? Ruby lets you perform this trick with
ObjectSpace
::
each_object

.


For example, to iterate over all objects of type Numeric, you'd
write the following.


a = 102.7


b = 95 # Won't be returned


c = 12345678987654321 # Won't be returned


count =
ObjectSpace.each_object
(Numeric) {|x| p x }


puts "Total count: #{count}“

Produces:

102.7

3.14159265358979

2.71828182845904

2.22044604925031e
-
16

1.79769313486232e+308

4.9e
-
324

Total count: 6


Hey, where did those last numbers come from? We didn't define
them in our program. The Math module defines constants for e
and PI; since we are examining
all

living objects in the system,
these turn up as well.


Right click on Project name,


Select Properties


Click Run


Define Ruby Option


For instance, we can get a list of all the methods to
which an object will respond.


r=1..10


num = 14


list =
r.methods


list.length

# 60


list[0..3]


# [
exclude_end
?,
to_a
, include?, member?]


r.respond_to
?("frozen?") #>> true


r.respond_to
?("
hasKey
") #>> true


num.instance_of
?

Fixnum

#>> true

one_class

=

Fixnum


begin




print

one_class





one_class

=

one_class

.
superclass




print

"

<

"

if

one_class



end

while

one_class



puts p

Fixnum.ancestors


puts
self.class

# scripts are automatically in Object

puts 3.class # numbers are
Fixnum


Produces

Fixnum
<Integer<Numeric<Object

[
Fixnum
, Integer, Precision, Numeric, Comparable, Object, Kernel]

Object

Fixnum


trane
="John

Coltrane".method
(:length)

miles="Miles
Davis".method
("sub")

puts
trane.call

puts
miles.call
(/
iles
/,'.')

trane
=%q{"John

Coltrane".length
}

miles=%q{"Miles
Davis".sub
(/
iles
/,'.')}

puts
eval

trane

puts
eval

miles

produces 14


M. Davis


14


M. Davis


class
CoinSlot


def initialize(amt)


@amt=amt


$here=binding


end

end

a=
CoinSlot.new
(35)

eval

("puts @amt", $here) # 35

eval

("puts @amt” ) # nil


At instance variable begins with @

and its scope is confined to
whatever object
self
refers to

A global variable begins with $

It can be referred to from anywhere

in the program

class
CoinSlot


def initialize(amt)


@amt=amt


$here=binding


end

end

a=
CoinSlot.new
(35)

eval

("puts @amt", $here) # 35

eval

("puts @amt” ) # nil

eval

"@amt=23.92", $here

eval

"puts @amt", $here # 23.92


We can even modify

variables in original scope


One nice feature of
globals
, is that they can
be traced; you can specify a procedure which
is invoked whenever the value of the variable
is changed.



trace_var

:$here, proc{print "$here is now",
$here, "
\
n"}

class Demo


def initialize(secret)


@secret = secret


end


def
getBinding


return binding()


end


end



k1 =
Demo.new
(99)


b1 = k1.getBinding


k2 =
Demo.new
(
-
3)


b2 = k2.getBinding



puts
eval
("@secret", b1) #=> 99


puts
eval
("@secret", b2) #=>
-
3


puts
eval
("@secret") #=> nil



caller is a Ruby method of the Kernel class,
which all objects inherit.


It returns an array of strings representing the
call stack.


class Demo


def initialize(secret)


@secret = secret


@other = 2*@secret


$here = binding


end


def
aA


puts
caller.join
("
\
n")


end


def
aB


aA


end


def
aC


aB


end


def
getBinding


return binding()


end


end


k1 =
Demo.new
(99)


k1.aC # prints call stack

Produces:


C
\
cs4700
\
simple_ruby_application
\
lib
\
Scoping.rb:25:in `
aB
'


C:
\
cs4700
\
simple_ruby_application
\
lib
\
Scoping.rb:28:in `
aC
'


C:
\
cs4700
\
simple_ruby_application
\
lib
\
Scoping.rb:49



Java features the ability to
serialize

objects,
letting you store them somewhere and
reconstitute them when needed. You might
use this facility, for instance, to save a tree of
objects that represent some portion of
application state, save it, and recreate is later.


Ruby calls this kind of serialization
marshalling
.


Marshal
: Def: To arrange or place (troops, for
example) in line for a parade, maneuver, or
review.


Can be used to create a distributed object
system.

class Note


attr

:value


def initialize(
val
)


@value =
val


end


def
to_s


@
value.to_s


end

end



class Chord


def initialize(
arr
)


@
arr

=
arr


end


def play


@
arr.join
('
-
')


end

end



c =
Chord.new
( [
Note.new
("G"),
Note.new
("Bb"),
Note.new
("Db"),
Note.new
("E") ] )



File.open
("posterity", "w+") do |f|


Marshal.dump
(c, f)

end



File.open
("posterity") do |f|


chord =
Marshal.load
(f)


puts
chord.play


#» G
-
Bb
-
Db
-
E


end


the format used by Marshal has changed a few
times in the past.


it's Ruby
-
only. AFAIK nothing else can read data
serialized with Marshal.


serializing objects with Marshal exposes
implementation details.


The basic problem with Marshal is that it
serializes an object by saving the name of its
class and all its instance variables


Makes interoperability harder


encoding may
change and implementation details are leaked by
default.

Using Ruby's alias it is possible to reopen a class, override a method and still call the original.



class
ClockRadio


def on!


@on = true


end




def on?


@on


end

end

Clock Radio is complete,

Sometime later we can redefine methods and add new ones:


class
ClockRadio


alias :
old_on
! :on!



def on!


old_on
!
# Calling original code


@
display_time

= true


end



def
display_time
?


@
display_time


end

end


The advantage you gain from being able to
reopen classes is that you can patch the
framework you’re using unobtrusively in order
to fix bugs or improve performance.


Violates OO principle by allowing anyone to add
members and methods to an existing class, even
outside of the original class definition.


The methods thus added have full access to all
other members and methods, including private
ones.


This is a “violation of the Open/Closed Principle,”
in that the original class is
not

kept closed
against modifications.


It certainly isn’t pure. There really isn’t a Grand
Unifying Idea. It clearly copies features from very
different languages and allows for a variety of
programming styles.

A closure is a nameless function.


It has code to run (the executable)


It has state around the code (the scope)


You capture the environment (the local variables)
in the closure.

Even after the function has returned, and its local
scope has been destroyed, the local variables
remain in existence as part of the closure object.

Local variables are shared between the closure and
the method. It's a real closure. It's not just a
copy. (This is a Perl feature that is copied.)



You can reconvert a closure back into a block, so
a closure can be used anywhere a block can be
used.


Often, closures are used to store the status of a
block into an instance variable, because once you
convert a block into a closure, it is an object that
can be referenced by a variable.


And of course closures can be used like they are
used in other languages, such as passing around
the object to customize behavior of methods.

The important thing to remember about Ruby
is that there isn't a big difference between
``compile time'' and ``runtime.‘’ This
allows:


adding code to a running process.


redefining methods on the fly, change their
scope from public to private, and so on.


altering basic types, such as Class and
Object.

eval

"puts 2+2" # => 4

eval

"'hello world!'.
upcase

“# => HELLO WORLD


Useful:


Tutoring


allows users to run their code in a
protected environment


evaluating math expression (like in spreadsheet)


more flexible than a parser as can call functions that
were just created.


implemented with the same interpreter as normal
code


Dangers:


input = # ... read from some form

eval

input

What if they input '
rm

-
rf

*‘ ?



Slow


string must be parsed


Side Effects: As an everyday example, the statement




x = gets

reads a line and sticks it into x just like you’d probably expect,
but it also has the side effect of sticking the line into the
global

variable $_.


Ruby also blurs the line between names of variables,
classes, and methods.


Some languages allow the
same identifier to be both a class and a variable, but
context distinguishes.
Ruby does not.


Ruby delights in the bizarre usage of operator
overloading. ”<<” normally means “left shift”, but it
also means ”
here document

follows,” “append to
string,” and “extend array.” Other operators have
similar illogical
overloadings
; for example, the ”<"
operator not only means "less than" but also "is a
subclass of."