Wikilibro programacion

Page 1

WIKILIBRO PROGRAMACION ALFREDO RIVERO


Índice general 1

2

PROGRAMACION

1

1.1

Programación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1

1.1.1

Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1

1.1.2

Léxico y programación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1

1.1.3

Programas y algoritmos

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2

1.1.4

Compilación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2

1.1.5

Programación e ingeniería del software

. . . . . . . . . . . . . . . . . . . . . . . . . . .

2

1.1.6

Referencias históricas

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3

1.1.7

Objetivos de la programación

1.1.8

Ciclo de vida del software

1.1.9

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4

1.1.10 Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5

1.1.11 Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5

TIPOS DE PROGRAMACION

6

2.1

Programación orientada a objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

2.1.1

Introducción

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

2.1.2

Origen

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

2.1.3

Conceptos fundamentales

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7

2.1.4

Características de la POO

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

8

2.1.5

Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

2.1.6

Algunos lenguajes orientados a objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

2.1.7

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

2.1.8

Notas y referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

2.1.9

Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

Programación estructurada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

2.2.1

Orígenes de la programación estructurada . . . . . . . . . . . . . . . . . . . . . . . . . .

11

2.2.2

Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12

2.2.3

Ventajas de la programación estructurada

. . . . . . . . . . . . . . . . . . . . . . . . . .

12

2.2.4

Lenguajes de programación estructurada . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

2.2.5

Nuevos paradigmas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

2.2.6

Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

2.2.7

Bibliografía . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

2.2

i


ii

ÍNDICE GENERAL

2.3

2.4 2.5

2.6

2.7

3

4

2.2.8

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

2.2.9

Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

Programación declarativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

2.3.1

Diferencia entre imperativo y declarativo

. . . . . . . . . . . . . . . . . . . . . . . . . .

14

2.3.2

Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

2.3.3

Ventajas

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

2.3.4

Algunos lenguajes declarativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

2.3.5

Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

Programación modular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

2.4.1

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

Programación en pareja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

2.5.1

Ventajas

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

2.5.2

Críticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

2.5.3

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

2.5.4

Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

Programación dinámica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

2.6.1

Introducción

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

2.6.2

Principio de optimalidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

2.6.3

Empleos

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

20

2.6.4

Ejercicios resueltos con programación dinámica . . . . . . . . . . . . . . . . . . . . . . .

22

2.6.5

Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

2.6.6

Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

Programación extrema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

2.7.1

Valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

2.7.2

Características fundamentales

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

2.7.3

Roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

2.7.4

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25

2.7.5

Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25

LENGUAJES

26

3.1

Lenguaje de programación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

3.1.1

Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27

3.1.2

Elementos

28

3.1.3

Implementación

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

33

3.1.4

Técnica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

3.1.5

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

3.1.6

Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

36

3.1.7

Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

36

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

TIPOS DE LENGUAJES

37

4.1

C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

37

4.1.1

38

Ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


ÍNDICE GENERAL

4.2

4.3

4.4

iii

4.1.2

Tipos de datos

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

4.1.3

Principios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

4.1.4

El concepto de clase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

4.1.5

Standard Template Library (STL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

46

4.1.6

Biblioteca de entrada y salida

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

46

4.1.7

C++11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

4.1.8

Actualidad y futuro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

49

4.1.9

Diferencias de tipos respecto a C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

49

4.1.10 Compiladores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

49

4.1.11 Ejemplo: Cmd con colores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

49

4.1.12 Entornos de desarrollo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

49

4.1.13 Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

50

4.1.14 Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

50

4.1.15 Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

51

Java (lenguaje de programación) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

51

4.2.1

Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

51

4.2.2

Filosofía

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

54

4.2.3

Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

56

4.2.4

Entornos de funcionamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

58

4.2.5

Programación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

4.2.6

Industria relacionada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

62

4.2.7

Críticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

62

4.2.8

Recursos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

4.2.9

Java en código abierto

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

65

4.2.10 Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

66

4.2.11 Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

66

4.2.12 Notas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

66

4.2.13 Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

67

JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

67

4.3.1

Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

4.3.2

Características . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

4.3.3

Sintaxis y semántica

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

71

4.3.4

Uso en páginas web

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

72

4.3.5

Seguridad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

74

4.3.6

Herramientas de desarrollo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

75

4.3.7

Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

75

4.3.8

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

77

4.3.9

Bibliografía . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

77

4.3.10 Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

77

PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

77

4.4.1

78

Etimología . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


iv

ÍNDICE GENERAL 4.4.2

Visión general

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

78

4.4.3

Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

78

4.4.4

Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

79

4.4.5

Características de PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

79

4.4.6

Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

4.4.7

Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

Visual Basic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

82

4.5.1

Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

82

4.5.2

Características . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

4.5.3

Objetos y eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

85

4.5.4

Ejemplo de código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

86

4.5.5

Ventajas

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

86

4.5.6

Desventajas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

86

4.5.7

Alternativas multiplataforma o externas a Windows . . . . . . . . . . . . . . . . . . . . .

86

4.5.8

Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

87

4.5.9

Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

87

Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

87

4.6.1

Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

87

4.6.2

Características y paradigmas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

88

4.6.3

Filosofía

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

89

4.6.4

Modo interactivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

89

4.6.5

Elementos del lenguaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

90

4.6.6

Sistema de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

94

4.6.7

Biblioteca estándar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

94

4.6.8

Implementaciones

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

94

4.6.9

Diferencias entre Python 2.x y Python 3.x . . . . . . . . . . . . . . . . . . . . . . . . . .

94

4.6.10 Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

95

4.6.11 Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

95

4.6.12 Bibliografía . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

96

4.6.13 Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

96

Lenguaje ensamblador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

96

4.7.1

Características . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

97

4.7.2

Programa ensamblador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

97

4.7.3

Lenguaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

98

4.7.4

Diseño del lenguaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100

4.7.5

Uso del lenguaje ensamblador

4.7.6

Detalles adicionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

4.7.7

Ejemplos de lenguaje ensamblador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

ANEXOS

114

4.5

4.6

4.7

5

5.1

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

Algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 5.1.1

Definición formal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114


ÍNDICE GENERAL

5.2

6

v

5.1.2

Medios de expresión de un algoritmo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

5.1.3

Algoritmos como funciones

5.1.4

Análisis de algoritmos

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

5.1.5

Ejemplo de algoritmo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

5.1.6

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120

5.1.7

Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

5.1.8

Bibliografía . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

5.1.9

Enlaces externos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

Estructura de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 5.2.1

Descripción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

5.2.2

Ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123

5.2.3

Soporte en los lenguajes

5.2.4

Estructuras de datos en programación . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

5.2.5

Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

5.2.6

Véase también . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

Origen del texto y las imágenes, colaboradores y licencias

125

6.1

Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

6.2

Imágenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

6.3

Licencia del contenido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131


Capítulo 1

PROGRAMACION 1.1 Programación La programación informática o programación algorítmica, acortada como programación, es el proceso de diseñar, codificar, depurar y mantener el código fuente de programas computacionales. El código fuente es escrito en un lenguaje de programación. El propósito de la programación es crear programas que exhiban un comportamiento deseado. El proceso de escribir código requiere frecuentemente conocimientos en varias áreas distintas, además del dominio del lenguaje a utilizar, algoritmos especializados y lógica formal. Programar no involucra necesariamente otras tareas tales como el análisis y diseño de la aplicación (pero sí el diseño del código), aunque sí suelen estar fusionadas en el desarrollo de pequeñas aplicaciones. Del proceso de programación surge lo que comúnmente se conoce como software (conjunto de programas), aunque estrictamente este último abarca mucho más que solo la programación.

1.1.1

Historia

Para crear un programa, y que la computadora lo interprete y ejecute las instrucciones escritas en él, debe escribirse en un lenguaje de programación. En sus inicios las computadoras interpretaban solo instrucciones en un lenguaje específico, del más bajo nivel, conocido como código máquina, siendo éste excesivamente complicado para programar. De hecho solo consiste en cadenas de números 1 y 0 (sistema binario). Para facilitar el trabajo de programación, los primeros científicos, que trabajaban en el área, decidieron reemplazar las instrucciones, secuencias de unos y ceros, por palabras o abreviaturas provenientes del inglés; las codificaron y crearon así un lenguaje de mayor nivel, que se conoce como Asembly o lenguaje ensamblador. Por ejemplo, para sumar se podría usar la letra A de la palabra inglesa add (sumar). En realidad escribir en lenguaje ensamblador es básicamente lo mismo que hacerlo en lenguaje máquina, pero las letras y palabras son bastante más fáciles de recordar y entender que secuencias de números binarios. A medida que la complejidad de las tareas que realizaban las computadoras aumentaba, se hizo necesario disponer de un método sencillo para programar. Entonces, se crearon los lenguajes de alto nivel. Mientras que una tarea tan trivial como multiplicar dos números puede necesitar un conjunto de instrucciones en lenguaje ensamblador, en un lenguaje de alto nivel bastará con solo una. Una vez que se termina de escribir un programa, sea en ensamblador o en algunos lenguajes de alto nivel, es necesario compilarlo, es decir, traducirlo completo a lenguaje máquina.[1] Eventualmente será necesaria otra fase denominada comúnmente link o enlace, durante la cual se anexan al código, generado durante la compilación, los recursos necesarios de alguna biblioteca. En algunos lenguajes de programación, puede no ser requerido el proceso de compilación y enlace, ya que pueden trabajar en modo intérprete. Esta modalidad de trabajo es equivalente pero se realiza instrucción por instrucción, a medida que es ejecutado el programa.

1.1.2

Léxico y programación

La programación se rige por reglas y un conjunto más o menos reducido de órdenes, expresiones, instrucciones y comandos que tienden a asemejarse a una lengua natural acotada (en inglés); y que además tienen la particularidad de una reducida ambigüedad. Cuanto menos ambiguo es un lenguaje de programación, se dice, es más potente. Bajo esta premisa, y en el extremo, el lenguaje más potente existente es el binario, con ambigüedad nula (lo cual lleva a 1


2

CAPÍTULO 1. PROGRAMACION

pensar así del lenguaje ensamblador). En los lenguajes de programación de alto nivel se distinguen diversos elementos entre los que se incluyen el léxico propio del lenguaje y las reglas semánticas y sintácticas.

1.1.3

Programas y algoritmos

Un algoritmo es una secuencia no ambigua, finita y ordenada de instrucciones que han de seguirse para resolver un problema. Un programa normalmente implementa (traduce a un lenguaje de programación concreto) uno o más algoritmos. Un algoritmo puede expresarse de distintas maneras: en forma gráfica, como un diagrama de flujo, en forma de código como en pseudocódigo o un lenguaje de programación, en forma explicativa, etc. Los programas suelen subdividirse en partes menores, llamadas módulos, de modo que la complejidad algorítmica de cada una de las partes sea menor que la del programa completo, lo cual ayuda al desarrollo del programa. Esta es una práctica muy utilizada y se conoce como “refino progresivo”. Según Niklaus Wirth, un programa está formado por los algoritmos y la estructura de datos. Se han propuesto diversas técnicas de programación cuyo objetivo es mejorar tanto el proceso de creación de software como su mantenimiento. Entre ellas, se pueden mencionar las siguientes: • Programación declarativa • Programación estructurada • Programación modular • Programación orientada a objetos

1.1.4

Compilación

El programa escrito en un lenguaje de programación de alto nivel (fácilmente comprensible por el programador) es llamado programa fuente y no se puede ejecutar directamente en una computadora. La opción más común es compilar el programa obteniendo un módulo objeto, aunque también puede ejecutarse en forma más directa a través de un intérprete informático. El código fuente del programa se debe someter a un proceso de traducción para convertirlo a lenguaje máquina o bien a un código intermedio, generando así un módulo denominado “objeto”. A este proceso se le llama compilación. Habitualmente la creación de un programa ejecutable (un típico.exe para Microsoft Windows o DOS) conlleva dos pasos. El primer paso se llama compilación (propiamente dicho) y traduce el código fuente escrito en un lenguaje de programación almacenado en un archivo de texto a código en bajo nivel (normalmente en código objeto, no directamente a lenguaje máquina). El segundo paso se llama enlazado en el cual se enlaza el código de bajo nivel generado de todos los ficheros y subprogramas que se han mandado compilar y se añade el código de las funciones que hay en las bibliotecas del compilador para que el ejecutable pueda comunicarse directamente con el sistema operativo, traduciendo así finalmente el código objeto a código máquina, y generando un módulo ejecutable. Estos dos pasos se pueden hacer por separado, almacenando el resultado de la fase de compilación en archivos objetos (un típico .o para Unix, .obj para MS-Windows, DOS); para enlazarlos en fases posteriores, o crear directamente el ejecutable; con lo que la fase de compilación puede almacenarse solo de forma temporal. Un programa podría tener partes escritas en varios lenguajes, por ejemplo, Java, C, C++ y ensamblador, que se podrían compilar de forma independiente y luego enlazar juntas para formar un único módulo ejecutable.

1.1.5

Programación e ingeniería del software

Existe una tendencia a identificar el proceso de creación de un programa informático con la programación, que es cierta cuando se trata de programas pequeños para uso personal, y que dista de la realidad cuando se trata de grandes proyectos. El proceso de creación de software, desde el punto de vista de la ingeniería, incluye mínimamente los siguientes pasos:


1.1. PROGRAMACIÓN

3

1. Reconocer la necesidad de un programa para solucionar un problema o identificar la posibilidad de automatización de una tarea. 2. Recoger los requisitos del programa. Debe quedar claro qué es lo que debe hacer el programa y para qué se necesita. 3. Realizar el análisis de los requisitos del programa. Debe quedar claro qué tareas debe realizar el programa. Las pruebas que comprueben la validez del programa se pueden especificar en esta fase. 4. Diseñar la arquitectura del programa. Se debe descomponer el programa en partes de complejidad abordable. 5. Implementar el programa. Consiste en realizar un diseño detallado, especificando completamente todo el funcionamiento del programa, tras lo cual la codificación (programación propiamente dicha) debería resultar inmediata. 6. Probar el programa. Comprobar que pasan pruebas que se han definido en el análisis de requisitos. 7. Implantar (instalar) el programa. Consiste en poner el programa en funcionamiento junto con los componentes que pueda necesitar (bases de datos, redes de comunicaciones, etc.). La ingeniería del software se centra en los pasos de planificación y diseño del programa, mientras que antiguamente (programación artesanal) la realización de un programa consistía casi únicamente en escribir el código, bajo solo el conocimiento de los requisitos y con una modesta fase de análisis y diseño.

1.1.6

Referencias históricas

El trabajo de Ada Lovelace, hija de Anabella Milbanke Byron y Lord Byron, realizó para la máquina de Babbage le hizo ganarse el título de primera programadora de computadoras del mundo, aunque Babbage nunca completó la construcción de la máquina. El nombre del lenguaje de programación Ada fue escogido como homenaje a esta programadora.

1.1.7

Objetivos de la programación

La programación debe perseguir la obtención de programas de calidad. Para ello se establece una serie de factores que determinan la calidad de un programa. Algunos de los factores de calidad más importantes son los siguientes: • Correctitud. Un programa es correcto si hace lo que debe hacer tal y como se estableció en las fases previas a su desarrollo. Para determinar si un programa hace lo que debe, es muy importante especificar claramente qué debe hacer el programa antes de su desarrollo y, una vez acabado, compararlo con lo que realmente hace. • Claridad. Es muy importante que el programa sea lo más claro y legible posible, para facilitar tanto su desarrollo como su posterior mantenimiento. Al elaborar un programa se debe intentar que su estructura sea sencilla y coherente, así como cuidar el estilo de programación. De esta forma se ve facilitado el trabajo del programador, tanto en la fase de creación como en las fases posteriores de corrección de errores, ampliaciones, modificaciones, etc. Fases que pueden ser realizadas incluso por otro programador, con lo cual la claridad es aún más necesaria para que otros puedan continuar el trabajo fácilmente. Algunos programadores llegan incluso a utilizar Arte ASCII para delimitar secciones de código; una práctica común es realizar aclaraciones en el código fuente utilizando líneas de comentarios. Contrariamente, algunos por diversión o para impedirle un análisis cómodo a otros programadores, recurren al uso de código ofuscado. • Eficiencia. Se trata de que el programa, además de realizar aquello para lo que fue creado (es decir, que sea correcto), lo haga gestionando de la mejor forma posible los recursos que utiliza. Normalmente, al hablar de eficiencia de un programa, se suele hacer referencia al tiempo que tarda en realizar la tarea para la que ha sido creado y a la cantidad de memoria que necesita, pero hay otros recursos que también pueden ser de consideración para mejorar la eficiencia de un programa, dependiendo de su naturaleza (espacio en disco que utiliza, tráfico en la red que genera, etc.).


4

CAPÍTULO 1. PROGRAMACION • Portabilidad. Un programa es portable cuando tiene la capacidad de poder ejecutarse en una plataforma, ya sea hardware o software, diferente a aquélla en la que se desarrolló. La portabilidad es una característica muy deseable para un programa, ya que permite, por ejemplo, a un programa que se ha elaborado para el sistema GNU/Linux ejecutarse también en la familia de sistemas operativos Windows. Esto permite que el programa pueda llegar a más usuarios más fácilmente.

1.1.8

Ciclo de vida del software

El término ciclo de vida del software describe el desarrollo de software, desde la fase inicial hasta la fase final, incluyendo su estado funcional. El propósito es definir las distintas fases intermedias que se requieren para validar el desarrollo de la aplicación, es decir, para garantizar que el software cumpla los requisitos para la aplicación y verificación de los procedimientos de desarrollo: se asegura que los métodos utilizados son apropiados. Estos métodos se originan en el hecho de que es muy costoso rectificar los errores que se detectan tarde dentro de la fase de implementación (programación propiamente dicha), o peor aun, durante la fase funcional. El modelo de ciclo de vida permite que los errores se detecten lo antes posible y por lo tanto, permite a los desarrolladores concentrarse en la calidad del software, en los plazos de implementación y en los costos asociados. El ciclo de vida básico de un software consta de, al menos, los siguientes procedimientos: • Definición de objetivos: definir el resultado del proyecto y su papel en la estrategia global. • Análisis de los requisitos y su viabilidad: recopilar, examinar y formular los requisitos del cliente y examinar cualquier restricción que se pueda aplicar. • Diseño general: requisitos generales de la arquitectura de la aplicación. • Diseño en detalle: definición precisa de cada subconjunto de la aplicación. • Programación (programación e implementación): es la implementación en un lenguaje de programación para crear las funciones definidas durante la etapa de diseño. • Prueba de unidad: prueba individual de cada subconjunto de la aplicación para garantizar que se implementaron de acuerdo con las especificaciones. • Integración: para garantizar que los diferentes módulos y subprogramas se integren con la aplicación. Éste es el propósito de la prueba de integración que debe estar cuidadosamente documentada. • Prueba beta (o validación), para garantizar que el software cumple con las especificaciones originales. • Documentación: se documenta con toda la información necesaria, sea funcional final para los usuarios del software (manual del usuario), y de desarrollo para futuras adaptaciones, ampliaciones y correcciones. • Mantenimiento: para todos los procedimientos correctivos (mantenimiento correctivo) y las actualizaciones secundarias del software (mantenimiento continuo). El orden y la presencia de cada uno de estos procedimientos en el ciclo de vida de una aplicación dependen del tipo de modelo de ciclo de vida acordado entre el cliente y el equipo de desarrolladores.

1.1.9

Véase también

• •

Portal:Programación. Contenido relacionado con Programación.

• Wikiproyecto:Informática/Programación • error de software • filosofías del desarrollo de software • historia de la ingeniería del software


1.1. PROGRAMACIÓN

5

• ingeniería en computación • Desarrollo De Software • ingeniería en informática • línea de código fuente • lenguaje de programación • programación automática • programación dirigida por eventos • programación estructurada • programación extrema • programación en pareja • programación dinámica • programación orientada a objetos • pruebas de software • software

1.1.10

Referencias

[1] Laboda, Xavier; Josep Galimany, Rosa María Pena, Antoni Gual (1985). «Software». Biblioteca práctica de la computación. Barcelona: Ediciones Océano-Éxito, S.A.

1.1.11

Enlaces externos

Wikimedia Commons alberga contenido multimedia sobre Programación. Commons

Wikcionario tiene definiciones y otra información sobre programación.Wikcionario

Wikiquote alberga frases célebres de o sobre Programación. Wikiquote

Wikilibros •

Wikilibros alberga un libro o manual sobre Fundamentos de programación.


Capítulo 2

TIPOS DE PROGRAMACION 2.1 Programación orientada a objetos La programación orientada a objetos (POO, u OOP según sus siglas en inglés) es un paradigma de programación que usa objetos en sus interacciones, para diseñar aplicaciones y programas informáticos. Está basada en varias técnicas, incluyendo herencia, cohesión, abstracción, polimorfismo, acoplamiento y encapsulamiento. Su uso se popularizó a principios de la década de 1990. En la actualidad, existe una gran variedad de lenguajes de programación que soportan la orientación a objetos.

2.1.1

Introducción

Los objetos son entidades que tienen un determinado “estado”, “comportamiento (método)" e “identidad": • La identidad es una propiedad de un objeto que lo diferencia del resto; dicho con otras palabras, es su identificador (concepto análogo al de identificador de una variable o una constante). Un objeto contiene toda la información que permite definirlo e identificarlo frente a otros objetos pertenecientes a otras clases e incluso frente a objetos de una misma clase, al poder tener valores bien diferenciados en sus atributos. A su vez, los objetos disponen de mecanismos de interacción llamados métodos, que favorecen la comunicación entre ellos. Esta comunicación favorece a su vez el cambio de estado en los propios objetos. Esta característica lleva a tratarlos como unidades indivisibles, en las que no se separa el estado y el comportamiento. Los métodos (comportamiento) y atributos (estado) están estrechamente relacionados por la propiedad de conjunto. Esta propiedad destaca que una clase requiere de métodos para poder tratar los atributos con los que cuenta. El programador debe pensar indistintamente en ambos conceptos, sin separar ni darle mayor importancia a alguno de ellos. Hacerlo podría producir el hábito erróneo de crear clases contenedoras de información por un lado y clases con métodos que manejen a las primeras por el otro. De esta manera se estaría realizando una "programación estructurada camuflada” en un lenguaje de POO. La programación orientada a objetos difiere de la programación estructurada tradicional, en la que los datos y los procedimientos están separados y sin relación, ya que lo único que se busca es el procesamiento de unos datos de entrada para obtener otros de salida. La programación estructurada anima al programador a pensar sobre todo en términos de procedimientos o funciones, y en segundo lugar en las estructuras de datos que esos procedimientos manejan. En la programación estructurada solo se escriben funciones que procesan datos. Los programadores que emplean POO, en cambio, primero definen objetos para luego enviarles mensajes solicitándoles que realicen sus métodos por sí mismos.

2.1.2

Origen

Los conceptos de la POO tienen origen en Simula 67, un lenguaje diseñado para hacer simulaciones, creado por OleJohan Dahl y Kristen Nygaard, del Centro de Cómputo Noruego en Oslo. En este centro se trabajaba en simulaciones 6


2.1. PROGRAMACIÓN ORIENTADA A OBJETOS

7

de naves, que fueron confundidas por la explosión combinatoria de cómo las diversas cualidades de diferentes naves podían afectar unas a las otras. La idea surgió al agrupar los diversos tipos de naves en diversas clases de objetos, siendo responsable cada clase de objetos de definir sus “propios” datos y comportamientos. Fueron refinados más tarde en Smalltalk, desarrollado en Simula en Xerox PARC (cuya primera versión fue escrita sobre Basic) pero diseñado para ser un sistema completamente dinámico en el cual los objetos se podrían crear y modificar “sobre la marcha” (en tiempo de ejecución) en lugar de tener un sistema basado en programas estáticos. La POO se fue convirtiendo en el estilo de programación dominante a mediados de los años 1980, en gran parte debido a la influencia de C++, una extensión del lenguaje de programación C. Su dominación fue consolidada gracias al auge de las interfaces gráficas de usuario, para las cuales la POO está particularmente bien adaptada. En este caso, se habla también de programación dirigida por eventos. Las características de orientación a objetos fueron agregadas a muchos lenguajes existentes durante ese tiempo, incluyendo Ada, BASIC, Lisp más Pascal, entre otros. La adición de estas características a los lenguajes que no fueron diseñados inicialmente para ellas condujo a menudo a problemas de compatibilidad y en la capacidad de mantenimiento del código. Los lenguajes orientados a objetos “puros”, por su parte, carecían de las características de las cuales muchos programadores habían venido a depender. Para saltar este obstáculo, se hicieron muchas tentativas para crear nuevos lenguajes basados en métodos orientados a objetos, pero permitiendo algunas características imperativas de maneras “seguras”. El lenguaje de programación Eiffel de Bertrand Meyer fue un temprano y moderadamente acertado lenguaje con esos objetivos, pero ahora ha sido esencialmente reemplazado por Java, en gran parte debido a la aparición de Internet y a la implementación de la máquina virtual Java en la mayoría de navegadores web. PHP en su versión 5 se ha modificado; soporta una orientación completa a objetos, cumpliendo todas las características propias de la orientación a objetos.

2.1.3

Conceptos fundamentales

La POO es una forma de programar que trata de encontrar una solución a estos problemas. Introduce nuevos conceptos, que superan y amplían conceptos antiguos ya conocidos. Entre ellos destacan los siguientes: Clase Definiciones de las propiedades y comportamiento de un tipo de objeto concreto. La instanciación es la lectura de estas definiciones y la creación de un objeto a partir de ella. Herencia Por ejemplo, herencia de la clase C a la clase D, es la facilidad mediante la cual la clase D hereda en ella cada uno de los atributos y operaciones de C, como si esos atributos y operaciones hubiesen sido definidos por la misma D. Por lo tanto, puede usar los mismos métodos y variables públicas declaradas en C. Los componentes registrados como “privados” (private) también se heredan, pero como no pertenecen a la clase, se mantienen escondidos al programador y sólo pueden ser accedidos a través de otros métodos públicos. Esto es así para mantener hegemónico el ideal de POO. Objeto Instancia de una clase. Entidad provista de un conjunto de propiedades o atributos (datos) y de comportamiento o funcionalidad (métodos), los mismos que consecuentemente reaccionan a eventos. Se corresponden con los objetos reales del mundo que nos rodea, o con objetos internos del sistema (del programa). Método Algoritmo asociado a un objeto (o a una clase de objetos), cuya ejecución se desencadena tras la recepción de un “mensaje”. Desde el punto de vista del comportamiento, es lo que el objeto puede hacer. Un método puede producir un cambio en las propiedades del objeto, o la generación de un “evento” con un nuevo mensaje para otro objeto del sistema. Evento Es un suceso en el sistema (tal como una interacción del usuario con la máquina, o un mensaje enviado por un objeto). El sistema maneja el evento enviando el mensaje adecuado al objeto pertinente. También se puede definir como evento la reacción que puede desencadenar un objeto; es decir, la acción que genera. Atributos Características que tiene la clase. Mensaje Una comunicación dirigida a un objeto, que le ordena que ejecute uno de sus métodos con ciertos parámetros asociados al evento que lo generó. Propiedad o atributo Contenedor de un tipo de datos asociados a un objeto (o a una clase de objetos), que hace los datos visibles desde fuera del objeto y esto se define como sus características predeterminadas, y cuyo valor puede ser alterado por la ejecución de algún método.


8

CAPÍTULO 2. TIPOS DE PROGRAMACION

Estado interno Es una variable que se declara privada, que puede ser únicamente accedida y alterada por un método del objeto, y que se utiliza para indicar distintas situaciones posibles para el objeto (o clase de objetos). No es visible al programador que maneja una instancia de la clase. Componentes de un objeto Atributos, identidad, relaciones y métodos. Identificación de un objeto Un objeto se representa por medio de una tabla o entidad que esté compuesta por sus atributos y funciones correspondientes. En comparación con un lenguaje imperativo, una “variable” no es más que un contenedor interno del atributo del objeto o de un estado interno, así como la “función” es un procedimiento interno del método del objeto.

2.1.4

Características de la POO

Existe un acuerdo acerca de qué características contempla la “orientación a objetos”. Las características siguientes son las más importantes:[1] Abstracción Denota las características esenciales de un objeto, donde se capturan sus comportamientos. Cada objeto en el sistema sirve como modelo de un “agente” abstracto que puede realizar trabajo, informar y cambiar su estado, y “comunicarse” con otros objetos en el sistema sin revelar “cómo” se implementan estas características. Los procesos, las funciones o los métodos pueden también ser abstraídos, y, cuando lo están, una variedad de técnicas son requeridas para ampliar una abstracción. El proceso de abstracción permite seleccionar las características relevantes dentro de un conjunto e identificar comportamientos comunes para definir nuevos tipos de entidades en el mundo real. La abstracción es clave en el proceso de análisis y diseño orientado a objetos, ya que mediante ella podemos llegar a armar un conjunto de clases que permitan modelar la realidad o el problema que se quiere atacar. Encapsulamiento Significa reunir todos los elementos que pueden considerarse pertenecientes a una misma entidad, al mismo nivel de abstracción. Esto permite aumentar la cohesión (diseño estructurado) de los componentes del sistema. Algunos autores confunden este concepto con el principio de ocultación, principalmente porque se suelen emplear conjuntamente. Polimorfismo Comportamientos diferentes, asociados a objetos distintos, pueden compartir el mismo nombre; al llamarlos por ese nombre se utilizará el comportamiento correspondiente al objeto que se esté usando. O, dicho de otro modo, las referencias y las colecciones de objetos pueden contener objetos de diferentes tipos, y la invocación de un comportamiento en una referencia producirá el comportamiento correcto para el tipo real del objeto referenciado. Cuando esto ocurre en “tiempo de ejecución”, esta última característica se llama asignación tardía o asignación dinámica. Algunos lenguajes proporcionan medios más estáticos (en “tiempo de compilación”) de polimorfismo, tales como las plantillas y la sobrecarga de operadores de C++. Herencia Las clases no se encuentran aisladas, sino que se relacionan entre sí, formando una jerarquía de clasificación. Los objetos heredan las propiedades y el comportamiento de todas las clases a las que pertenecen. La herencia organiza y facilita el polimorfismo y el encapsulamiento, permitiendo a los objetos ser definidos y creados como tipos especializados de objetos preexistentes. Estos pueden compartir (y extender) su comportamiento sin tener que volver a implementarlo. Esto suele hacerse habitualmente agrupando los objetos en clases y estas en árboles o enrejados que reflejan un comportamiento común. Cuando un objeto hereda de más de una clase se dice que hay herencia múltiple; siendo de alta complejidad técnica por lo cual suele recurrirse a la herencia virtual para evitar la duplicación de datos. Modularidad Se denomina “modularidad” a la propiedad que permite subdividir una aplicación en partes más pequeñas (llamadas módulos), cada una de las cuales debe ser tan independiente como sea posible de la aplicación en sí y de las restantes partes. Estos módulos se pueden compilar por separado, pero tienen conexiones con otros módulos. Al igual que la encapsulación, los lenguajes soportan la modularidad de diversas formas. Principio de ocultación Cada objeto está aislado del exterior, es un módulo natural, y cada tipo de objeto expone una “interfaz” a otros objetos que especifica cómo pueden interactuar con los objetos de la clase. El aislamiento protege a las propiedades de un objeto contra su modificación por quien no tenga derecho a acceder a ellas; solamente los propios métodos internos del objeto pueden acceder a su estado. Esto asegura que otros objetos no puedan cambiar el estado interno de un objeto de manera inesperada, eliminando efectos secundarios e interacciones inesperadas. Algunos lenguajes relajan esto, permitiendo un acceso directo a los datos internos


2.1. PROGRAMACIÓN ORIENTADA A OBJETOS

9

del objeto de una manera controlada y limitando el grado de abstracción. La aplicación entera se reduce a un agregado o rompecabezas de objetos. Recolección de basura La recolección de basura (garbage collection) es la técnica por la cual el entorno de objetos se encarga de destruir automáticamente, y por tanto desvincular la memoria asociada, los objetos que hayan quedado sin ninguna referencia a ellos. Esto significa que el programador no debe preocuparse por la asignación o liberación de memoria, ya que el entorno la asignará al crear un nuevo objeto y la liberará cuando nadie lo esté usando. En la mayoría de los lenguajes híbridos que se extendieron para soportar el Paradigma de Programación Orientada a Objetos como C++ u Object Pascal, esta característica no existe y la memoria debe desasignarse expresamente.

2.1.5

Resumen

La POO es un paradigma surgido en los años 1970, que utiliza objetos como elementos fundamentales en la construcción de la solución. Un objeto es una abstracción de algún hecho o ente del mundo real, con atributos que representan sus características o propiedades, y métodos que emulan su comportamiento o actividad. Todas las propiedades y métodos comunes a los objetos se encapsulan o agrupan en clases. Una clase es una plantilla, un prototipo para crear objetos; en general, se dice que cada objeto es una instancia o ejemplar de una clase.

2.1.6

Algunos lenguajes orientados a objetos

Simula (1967) es aceptado como el primer lenguaje que posee las características principales de un lenguaje orientado a objetos. Fue creado para hacer programas de simulación, en donde los “objetos” son la representación de la información más importante. Smalltalk (1972 a 1980) es posiblemente el ejemplo canónico, y con el que gran parte de la teoría de la programación orientada a objetos se ha desarrollado. Entre los lenguajes orientados a objetos se destacan los siguientes: • ABAP[2] • ABL[3] • ActionScript • ActionScript 3 • Ada • C++ • C Sharp (C#) • Clarion • Clipper[4] • D • Object Pascal (Embarcadero Delphi) • Gambas • GObject • Genie • Harbour • Eiffel • Fortran 90/95


10

CAPÍTULO 2. TIPOS DE PROGRAMACION • Java • JavaScript[5] • Lexico[6] • Objective-C • Ocaml • Oz • R • Pauscal (en español) • Perl[7][8] • PHP[9] • PowerBuilder • Python • Ruby • Self • Smalltalk[10] • Magik (SmallWorld) • Vala • VB.NET • Visual FoxPro[11] • Visual Basic 6.0 • Visual DataFlex • Visual Objects • XBase++ • DRP • Scala[12][13]

Muchos de estos lenguajes de programación no son puramente orientados a objetos, sino que son híbridos que combinan la POO con otros paradigmas. Al igual que C++, otros lenguajes, como OOCOBOL, OOLisp, OOProlog y Object REXX, han sido creados añadiendo extensiones orientadas a objetos a un lenguaje de programación clásico. Un nuevo paso en la abstracción de paradigmas de programación es la Programación Orientada a Aspectos (POA). Aunque es todavía una metodología en estado de maduración, cada vez atrae a más investigadores e incluso proyectos comerciales en todo el mundo.

2.1.7

Véase también

• Base de datos orientada a objetos • Ingeniería de software basada en componentes


2.2. PROGRAMACIÓN ESTRUCTURADA

2.1.8

11

Notas y referencias

[1] Coad, P; Yourdon, E. (1991). Prentice-Hall International editions, ed. Object-oriented Design. ISBN 9780136300700. [2] SAP Business Suite (de la empresa SAP AG), lenguaje orientado a eventos. [3] Lenguaje de programación de OpenEdge de Progress Software. [4] Versión 5.x con librería de objetos Class(y). [5] La herencia se realiza por medio de la programación basada en prototipos. [6] En español. [7] Soporta herencia múltiple. La resolución se realiza en estructura de árbol (preorden), pero puede modificarse al algoritmo linearization C3 por medio del módulo Class::C3 en CPAN). [8] Class::C3. [9] PHP: a partir de su versión 5. [10] Entorno de objetos puro. [11] Visual FoxPro: en su versión 6. [12] Lenguaje de programación usado por Twitter. [13] http://www.scala-lang.org/page.jsp

2.1.9

Enlaces externos

• Qué es la programación orientada a objetos.

2.2 Programación estructurada La programación estructurada es un paradigma de programación orientado a mejorar la claridad, calidad y tiempo de desarrollo de un programa de computadora, utilizando únicamente subrutinas y tres estructuras: secuencia, selección (if y switch) e iteración (bucles for y while), considerando innecesario y contraproducente el uso de la instrucción de transferencia incondicional (GOTO), que podría conducir a "código espagueti", que es mucho más difícil de seguir y de mantener, y era la causa de muchos errores de programación. Surgió en la década de 1960, particularmente del trabajo de Böhm y Jacopini,[1] y una famosa carta, «La sentencia goto considerada perjudicial», de Edsger Dijkstra en 1968[2] — y fue reforzado teóricamente por el teorema del programa estructurado, y prácticamente por la aparición de lenguajes como ALGOL con adecuadas y ricas estructuras de control.

2.2.1

Orígenes de la programación estructurada

A finales de los años 1970 surgió una nueva forma de programar que no solamente daba lugar a programas fiables y eficientes, sino que además estaban escritos de manera que facilitaba su mejor comprensión, no sólo proveyendo ventajas durante la fase de desarrollo, sino también posibilitando una más sencilla modificación posterior. El teorema del programa estructurado, propuesto por Böhm-Jacopini, demuestra que todo programa puede escribirse utilizando únicamente las tres instrucciones de control siguientes: • Secuencia • Instrucción condicional. • Iteración (bucle de instrucciones) con condición al principio. Solamente con estas tres estructuras se pueden escribir todos los programas y aplicaciones posibles. Si bien los lenguajes de programación tienen un mayor repertorio de estructuras de control, estas pueden ser construidas mediante las tres básicas citadas.


12

CAPÍTULO 2. TIPOS DE PROGRAMACION

2.2.2

Historia

Fundamentación teórica El teorema del programa estructurado proporciona la base teórica de la programación estructurada. Señala que tres maneras de combinar programas son suficientes para expresar cualquier función computable: secuencia, selección e iteración. Esta observación no se originó con el movimiento de la programación estructurada. Estas estructuras son suficientes para describir el ciclo de instrucción de una unidad central de procesamiento, así como el funcionamiento de una máquina de Turing. Por lo tanto un procesador siempre está ejecutando un “programa estructurado” en este sentido, incluso si las instrucciones que lee de la memoria no son parte de un programa estructurado. Sin embargo, los autores usualmente acreditan el resultado a un documento escrito en 1966 por Böhm y Jacopini, posiblemente porque Dijkstra había citado este escrito. El teorema del programa estructurado no responde a cómo escribir y analizar un programa estructurado de manera útil. Estos temas fueron abordados durante la década de 1960 y principio de los años 1970, con importantes contribuciones de Dijkstra, Robert W. Floyd, Tony Hoarey y David Gries.

Debate P. J. Plauger, uno de los primeros en adoptar la programación estructurada, describió su reacción con el teorema del programa estructurado: Nosotros los conversos ondeamos esta interesante pizca de noticias bajo las narices de los recalcitrantes programadores de lenguaje ensamblador que mantuvieron trotando adelante retorcidos bits de lógica y diciendo, 'Te apuesto que no puedes estructurar esto'. Ni la prueba por Böhm y Jacopini, ni nuestros repetidos éxitos en escribir código estructurado, los llevaron un día antes de lo que estaban listos para convencerse.[3] Donald Knuth aceptó el principio de que los programas deben escribirse con demostratividad en mente, pero no estaba de acuerdo (y aún está en desacuerdo)[cita requerida] con la supresión de la sentencia GOTO. En su escrito de 1974 “Programación estructurada con sentencias Goto”, dio ejemplos donde creía que un salto directo conduce a código más claro y más eficiente sin sacrificar demostratividad. Knuth propuso una restricción estructural más flexible: debe ser posible establecer un diagrama de flujo del programa con todas las bifurcaciones hacia adelante a la izquierda, todas las bifurcaciones hacia atrás a la derecha, y sin bifurcaciones que se crucen entre sí. Muchos de los expertos en teoría de grafos y compiladores han abogado por permitir sólo grafos de flujo reducible[¿quién?][¿cuándo?] . Los teóricos de la programación estructurada ganaron a un aliado importante en la década de 1970 después de que el investigador de IBM Harlan Mills aplicara su interpretación de la teoría de la programación estructurada para el desarrollo de un sistema de indexación para el archivo de investigación del New York Times. El proyecto fue un gran éxito de la ingeniería, y los directivos de otras empresas lo citaron en apoyo de la adopción de la programación estructurada, aunque Dijkstra criticó las maneras en que la interpretación de Mills difería de la obra publicada. Tan tarde como 1987 fue todavía posible elevar la cuestión de la programación estructurada en una revista de ciencia de la computación. Frank Rubin lo hizo en ese año, con una carta, “La sentencia GOTO considerada dañina”. Numerosas objeciones siguieron, incluyendo una respuesta de Dijkstra, que criticaba duramente a Rubin y las concesiones que otros escritores hicieron cuando le respondieron.

Resultado A finales del siglo XX casi todos los científicos están convencidos de que es útil aprender y aplicar los conceptos de programación estructurada. Los lenguajes de programación de alto nivel que originalmente carecían de estructuras de programación, como FORTRAN, COBOL y BASIC, ahora las tienen.

2.2.3

Ventajas de la programación estructurada

Ventajas de la programación estructurada comparada con el modelo anterior (hoy llamado despectivamente código espagueti).


2.2. PROGRAMACIÓN ESTRUCTURADA

13

• Los programas son más fáciles de entender, pueden ser leídos de forma secuencial y no hay necesidad de hacer engorrosos seguimientos en saltos de líneas (GOTO) dentro de los bloques de código para intentar entender la lógica. • La estructura de los programas es clara, puesto que las instrucciones están más ligadas o relacionadas entre sí. • Reducción del esfuerzo en las pruebas y depuración. El seguimiento de los fallos o errores del programa (debugging) se facilita debido a su estructura más sencilla y comprensible, por lo que los errores se pueden detectar y corregir más fácilmente. • Reducción de los costos de mantenimiento. Análogamente a la depuración, durante la fase de mantenimiento, modificar o extender los programas resulta más fácil. • Los programas son más sencillos y más rápidos de confeccionar. • Se incrementa el rendimiento de los programadores.

2.2.4

Lenguajes de programación estructurada

Es posible hacer la programación estructurada en cualquier lenguaje de programación, aunque es preferible usar algo como un lenguaje de programación procedimental. Algunos de los lenguajes utilizados inicialmente para programación estructurada incluyen: ALGOL, Pascal, PL/I y Ada —pero la mayoría de los nuevos lenguajes de programación procedimentales desde entonces han incluido características para fomentar la programación estructurada y a veces deliberadamente omiten características,[4] en un esfuerzo para hacer más difícil la programación no estructurada.

2.2.5

Nuevos paradigmas

Posteriormente a la programación estructurada se han creado nuevos paradigmas tales como la programación modular, la programación orientada a objetos, programación por capas, etc., y el desarrollo de entornos de programación que facilitan la programación de grandes aplicaciones y sistemas.

2.2.6

Referencias

[1] Böhm, Jacopini. “Flow diagrams, turing machines and languages with only two formation rules” Comm. ACM, 9(5):366371, May 1966 [2] Edsger Dijkstra (marzo de 1968). «Go To Statement Considered Harmful». Communications of the ACM (PDF) 11 (3): 147-148. doi:10.1145/362929.362947. «The unbridled use of the go to statement has as an immediate consequence that it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress. ... The go to statement as it stands is just too primitive, it is too much an invitation to make a mess of one’s program.» [3] napellidos = Plauger (nombre = P. J. penlaceautor = P. J. Plauger stítulo = Programming on Purpose, Essays on Software Design rfecha = 12 de febrero de 1993 reditorial = Prentice-Hall sedición = 1 cisbn = 978-0-13-721374-0 dpágina = 25 a páginas = 256 [4] GOTO for example

2.2.7

Bibliografía

1. García-Bermejo Giner, José Rafael (2008). Programación estructurada en C (1.ª edición). Pearson Prentice Hall. ISBN 978-84-8322-423-6. 2. Valls Ferrán, José María; Camacho Fernández, David (2004). Programación estructurada y algoritmos en Pascal (1.ª edición). Pearson Alhambra. ISBN 978-84-205-4246-1. 3. Programación estructurada II (1.ª edición). Enseñanza Técnica y Sistemas, S.A. 2000. ISBN 978-84-85838-90-5. 4. Pseudocódigos y programación estructurada (1.ª edición). Centro Técnico Europeo de Enseñanzas Profesionales. 1997. ISBN 978-84-8199-065-2. 5. Sánchez Andrés, María Ángeles (1996). Programación estructurada y fundamentos de programación (1.ª edición). McGraw-Hill / Interamericana de España, S.A. ISBN 978-84-481-0557-0.


14

CAPÍTULO 2. TIPOS DE PROGRAMACION

2.2.8

Véase también

• Teorema del programa estructurado • Diseño estructurado • Bloque de código • Estructuras de control • Programación por procedimientos • Programación modular • Programación orientada a objetos

2.2.9

Enlaces externos

• Monografias.com: Programación Estructurada • Ejercicios resueltos de Programación Estructurada

2.3 Programación declarativa La Programación Declarativa, en contraposición a la programación imperativa es un paradigma de programación que está basado en el desarrollo de programas especificando o “declarando” un conjunto de condiciones, proposiciones, afirmaciones, restricciones, ecuaciones o transformaciones que describen el problema y detallan su solución. La solución es obtenida mediante mecanismos internos de control, sin especificar exactamente cómo encontrarla (tan sólo se le indica a la computadora qué es lo que se desea obtener o qué es lo que se está buscando). No existen asignaciones destructivas, y las variables son utilizadas con Transparencia referencial

2.3.1

Diferencia entre imperativo y declarativo

En la programación imperativa se describe paso a paso un conjunto de instrucciones que deben ejecutarse para variar el estado del programa y hallar la solución, es decir, un algoritmo en el que se describen los pasos necesarios para solucionar el problema. En la programación declarativa las sentencias que se utilizan lo que hacen es describir el problema que se quiere solucionar, se programa diciendo lo que se quiere resolver pero a nivel de usuario, pero no las instrucciones necesarias para solucionarlo. Esto último se realizará mediante mecanismos internos de inferencia de información a partir de la descripción realizada.

2.3.2

Tipos

Existen varios tipos de lenguajes declarativos: • Los lenguajes lógicos, como Prolog. • Los lenguajes algebraicos, como Maude y SQL • Los lenguajes funcionales, como Haskell y Erlang

2.3.3

Ventajas

Se ha dicho que los lenguajes declarativos tienen la ventaja de ser razonados matemáticamente, lo que permite el uso de mecanismos matemáticos para optimizar el rendimiento de los programas.[1] Son fiables, elegantes y expresivos.


2.4. PROGRAMACIÓN MODULAR

2.3.4

15

Algunos lenguajes declarativos

• ASP (Answer Set Programming) • Haskell (Programación funcional) • ML (Programación funcional) • Lisp (Programación funcional) • Prolog (Programación Lógica) • F-Prolog (Programación Lógica Difusa) • Curry (Programación Lógico-Funcional) • SQL • QML

2.3.5

Referencias

[1] http://ademirar.wordpress.com/2010/08/28/programacion-funcional-para-el-resto-de-nosotros/

2.4 Programación modular La programación modular es un paradigma de programación que consiste en dividir un programa en módulos o subprogramas con el fin de hacerlo más legible y manejable. Se presenta históricamente como una evolución de la programación estructurada para solucionar problemas de programación más grandes y complejos de lo que esta puede resolver. Al aplicar la programación modular, un problema complejo debe ser dividido en varios subproblemas más simples, y estos a su vez en otros subproblemas más simples. Esto debe hacerse hasta obtener subproblemas lo suficientemente simples como para poder ser resueltos fácilmente con algún lenguaje de programación. Esta técnica se llama refinamiento sucesivo, divide y vencerás ó análisis descendente (Top-Down). Un 'módulo' es cada una de las partes de un programa que resuelve uno de los subproblemas en que se divide el problema complejo original. Cada uno de estos módulos tiene una tarea bien definida y algunos necesitan de otros para poder operar. En caso de que un módulo necesite de otro, puede comunicarse con éste mediante una interfaz de comunicación que también debe estar bien definida. Si bien un módulo puede entenderse como una parte de un programa en cualquiera de sus formas y variados contextos, en la práctica se los suele tomar como sinónimos de procedimientos y funciones. Pero no necesaria ni estrictamente un módulo es una función o un procedimiento, ya que el mismo puede contener muchos de ellos. No debe confundirse el término “módulo” (en el sentido de programación modular) con términos como “función” o “procedimiento”, propios del lenguaje que lo soporte.

2.4.1

Véase también

• Módulo • Modularidad • Diseño estructurado • Programación estructurada • Programación por procedimientos • Programación orientada a objetos • Programación orientada a aspectos • Ingeniería de software basada en componentes


16

CAPÍTULO 2. TIPOS DE PROGRAMACION

Entrada

Parámetros

Proceso

Subrutina o función

Salida

Valor de retorno

Diagrama del funcionamiento de un subprograma.

2.5 Programación en pareja La Programación en Pareja (o Pair Programming en inglés) requiere que dos programadores participen en un esfuerzo combinado de desarrollo en un sitio de trabajo. Cada miembro realiza una acción que el otro no está haciendo actualmente: Mientras que uno codifica las pruebas de unidades el otro piensa en la clase que satisfará la prueba, por ejemplo. La persona que está haciendo la codificación se le da el nombre de controlador mientras que a la persona que está dirigiendo se le llama el navegador. Se sugiere a menudo para que a los dos socios cambien de papeles por lo menos cada media hora o después de que se haga una prueba de unidad.

2.5.1

Ventajas

La programación en pareja se enfoca en las siguientes ventajas, ordenadas de mayor a menor. • Más Disciplina. Emparejando correctamente es más probable que hagan “lo que se debe hacer” en lugar de tomar largos descansos.


2.5. PROGRAMACIÓN EN PAREJA

17

Programación en pareja

• Mejor código. Emparejando similares es menos probable producir malos diseños ya que su inmersión tiende a diseñar con mayor calidad. • Flujo de trabajo constante. El emparejamiento produce un flujo de trabajo distinto al trabajar solo. En pareja el flujo de trabajo se recupera más rápidamente: un programador pregunta al otro "¿por dónde quedamos?". Las parejas son más resistentes a las interrupciones ya que un desarrollador se ocupa de la interrupción mientras el otro continúa trabajando. • Múltiples desarrolladores contribuyen al diseño. Si las parejas rotan con frecuencia en el proyecto significa que más personas están involucradas con una característica en particular. Esto ayuda a crear mejores soluciones, especialmente cuando una pareja no puede resolver un problema difícil. • Moral mejorada. La programación en parejas es más agradable para algunos programadores, que programar solos. • Propiedad colectiva del código. Cuando el proyecto se hace en parejas, y las parejas se rotan con frecuencia, todos tienen un conocimiento del código base. • Enseñanza. Todos, hasta los novatos, poseen conocimientos que los otros no. La programación en pareja es una forma amena de compartir conocimientos. • Cohesión de equipo. La gente se familiariza más rápidamente cuando programa en pareja. La programación en pareja puede animar el sentimiento de equipo. • Pocas interrupciones. La gente es más renuente a interrumpir a una pareja que a una persona que trabaja sola. • Menos estaciones de trabajo. Ya que dos personas van a trabajar en una estación de trabajo, se requieren menos estaciones de trabajo, y las estaciones extras pueden ser ocupadas para otros propósitos. Los estudios han demostrado que después de entrenar para las “habilidades sociales” implicadas, parejas de programadores son más de dos veces más productivos que uno para una tarea dada. Según The Economist:


18

CAPÍTULO 2. TIPOS DE PROGRAMACION “Laurie Williams de la universidad de Utah en Salt Lake City ha demostrado que los programadores emparejados son solamente 15% más lentos de dos programadores trabajando independientemente, pero producen 15% menos errores. Y ya que la prueba y depuración son a menudo muchas veces más costosa que la programación inicial, esto es da un resultado impresionante” (Dr. Williams is currently Assistant Professor of Computer Science at North Carolina State University)

Un estudio reciente sobre un experimento rigurosamente científico en el cual se compara parejas de novatos contra novatos solos son mucho más productivos que parejas de expertos contra expertos solos, de acuerdo con “Int J. of Human Computer Studies Vol (64) 2006”

2.5.2

Críticas

• Desarrolladores expertos pueden encontrar tedioso enseñar a un desarrollador menos experimentado en un ambiente emparejado. • Muchos desarrolladores prefieren trabajar solos y encuentran el ambiente emparejado incómodo. • La productividad es difícil de medir, para comparar desarrolladores en parejas contra desarrolladores trabajando solos, usan métricas de programación que son controvertidas en el mejor de los casos. • Diferencias en el estilo de codificación pueden resultar en conflictos, aunque esto a su vez promueve la normalización (estandarización), para que todo el mundo pueda entender el código. • En caso de que la pareja tenga cronogramas de trabajo ligeramente distintos, lo cual es común en un ambiente que valora el balance trabajo - vida, la pareja solo funcionara en la intersección de los cronogramas. Por lo tanto, se requieren más horas persona para completar una tarea, un día típico tiene menos horas en pareja, lo cual incrementa el tiempo para completar la tarea. • Una compañía que funciona con Teletrabajo (trabajo desde el hogar o a distancia) o cuando un empleado debe trabajar desde afuera de las oficinas por cualquier razón, la programación en pareja se hace difícil o hasta imposible.

2.5.3

Véase también

• Programación Extrema

2.5.4

Enlaces externos

• VS Anywhere https://vsanywhere.com/web/

2.6 Programación dinámica En informática, la programación dinámica es un método para reducir el tiempo de ejecución de un algoritmo mediante la utilización de subproblemas superpuestos y subestructuras óptimas, como se describe a continuación. El matemático Richard Bellman inventó la programación dinámica en 1953 que se utiliza para optimizar problemas complejos que pueden ser discretizados y secuencializados.

2.6.1

Introducción

Una subestructura óptima significa que se pueden usar soluciones óptimas de subproblemas para encontrar la solución óptima del problema en su conjunto. Por ejemplo, el camino más corto entre dos vértices de un grafo se puede encontrar calculando primero el camino más corto al objetivo desde todos los vértices adyacentes al de partida, y después usando estas soluciones para elegir el mejor camino de todos ellos. En general, se pueden resolver problemas con subestructuras óptimas siguiendo estos tres pasos:


2.6. PROGRAMACIÓN DINÁMICA

19

1. Dividir el problema en subproblemas más pequeños. 2. Resolver estos problemas de manera óptima usando este proceso de tres pasos recursivamente. 3. Usar estas soluciones óptimas para construir una solución óptima al problema original. Los subproblemas se resuelven a su vez dividiéndolos en subproblemas más pequeños hasta que se alcance el caso fácil, donde la solución al problema es trivial. Decir que un problema tiene subproblemas superpuestos es decir que se usa un mismo subproblema para resolver diferentes problemas mayores. Por ejemplo, en la sucesión de Fibonacci (F3 = F1 + F2 y F4 = F2 + F3 ) calcular cada término supone calcular F2 . Como para calcular F5 hacen falta tanto F3 como F4 , una mala implementación para calcular F5 acabará calculando F2 dos o más veces. Esto sucede siempre que haya subproblemas superpuestos: una mala implementación puede acabar desperdiciando tiempo recalculando las soluciones óptimas a problemas que ya han sido resueltos anteriormente. Esto se puede evitar guardando las soluciones que ya hemos calculado. Entonces, si necesitamos resolver el mismo problema más tarde, podemos obtener la solución de la lista de soluciones calculadas y reutilizarla. Este acercamiento al problema se llama memoización (no confundir con memorización; en inglés es llamado memoization, véase en). Si estamos seguros de que no volveremos a necesitar una solución en concreto, la podemos descartar para ahorrar espacio. En algunos casos, podemos calcular las soluciones a problemas que de antemano sabemos que vamos a necesitar. En resumen, la programación hace uso de: • Subproblemas superpuestos • Subestructuras óptimas • Memoización La programación toma normalmente uno de los dos siguientes enfoques: • Top-down: El problema se divide en subproblemas, y estos se resuelven recordando las soluciones por si fueran necesarias nuevamente. Es una combinación de memoización y recursión. • Bottom-up: Todos los problemas que puedan ser necesarios se resuelven de antemano y después se usan para resolver las soluciones a problemas mayores. Este enfoque es ligeramente mejor en consumo de espacio y llamadas a funciones, pero a veces resulta poco intuitivo encontrar todos los subproblemas necesarios para resolver un problema dado. Originalmente, el término de programación dinámica se refería a la resolución de ciertos problemas y operaciones fuera del ámbito de la Ingeniería Informática, al igual que hacía la programación lineal. Aquel contexto no tiene relación con la programación en absoluto; el nombre es una coincidencia. El término también lo usó en los años 40 Richard Bellman, un matemático norteamericano, para describir el proceso de resolución de problemas donde hace falta calcular la mejor solución consecutivamente. Algunos lenguajes de programación funcionales, sobre todo Haskell, pueden usar la memorización automáticamente sobre funciones con un conjunto concreto de argumentos, para acelerar su proceso de evaluación. Esto sólo es posible en funciones que no tengan efectos secundarios, algo que ocurre en Haskell pero no tanto en otros lenguajes.

2.6.2

Principio de optimalidad

Cuando hablamos de optimizar nos referimos a buscar alguna de las mejores soluciones de entre muchas alternativas posibles. Dicho proceso de optimización puede ser visto como una secuencia de decisiones que nos proporcionan la solución correcta. Si, dada una subsecuencia de decisiones, siempre se conoce cuál es la decisión que debe tomarse a continuación para obtener la secuencia óptima, el problema es elemental y se resuelve trivialmente tomando una decisión detrás de otra, lo que se conoce como estrategia voraz. En otros casos, aunque no sea posible aplicar la estrategia voraz, se cumple el principio de optimalidad de Bellman que dicta que «dada una secuencia óptima de decisiones, toda subsecuencia de ella es, a su vez, óptima». En este caso sigue siendo posible el ir tomando decisiones elementales, en la confianza de que la combinación de ellas seguirá siendo óptima, pero será entonces necesario


20

CAPÍTULO 2. TIPOS DE PROGRAMACION

explorar muchas secuencias de decisiones para dar con la correcta, siendo aquí donde interviene la programación dinámica. Contemplar un problema como una secuencia de decisiones equivale a dividirlo en problemas más pequeños y por lo tanto más fáciles de resolver como hacemos en Divide y Vencerás, técnica similar a la de programación dinámica. La programación dinámica se aplica cuando la subdivisión de un problema conduce a: • Una enorme cantidad de problemas. • Problemas cuyas soluciones parciales se solapan. • Grupos de problemas de muy distinta complejidad.

2.6.3

Empleos

Sucesión de Fibonacci Esta sucesión puede expresarse mediante la siguiente recurrencia:   si n = 0 0 F ib(n) = 1 si n = 1   F ib(n − 1) + F ib(n − 2) si n > 1 Una implementación de una función que encuentre el n-ésimo término de la sucesión de Fibonacci basada directamente en la definición matemática de la sucesión realizando llamadas recursivas hace mucho trabajo redundante, obteniéndose una complejidad exponencial: FUNC fib(↓n: NATURAL): NATURAL INICIO SI n = 0 ENTONCES DEVOLVER 0 SI NO, SI n = 1 ENTONCES DEVOLVER 1 SI NO devolver fib(n-1) + fib(n-2) FIN SI FIN Si llamamos, por ejemplo, a fib(5), produciremos un árbol de llamadas que contendrá funciones con los mismos parámetros varias veces: 1. fib(5) 2. fib(4) + fib(3) 3. (fib(3) + fib(2)) + (fib(2) + fib(1)) 4. ((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1)) 5. (((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1)) En particular, fib(2) se ha calculado dos veces desde cero. En ejemplos mayores, se recalculan muchos otros valores de fib, o subproblemas. Para evitar este inconveniente, podemos resolver el problema mediante programación dinámica, y en particular, utilizando el enfoque de memorización (guardar los valores que ya han sido calculados para utilizarlos posteriormente). Así, rellenaríamos una tabla con los resultados de los distintos subproblemas, para reutilizarlos cuando haga falta en lugar de volver a calcularlos. La tabla resultante sería una tabla unidimensional con los resultados desde 0 hasta n. Un programa que calculase esto, usando Bottom-up, tendría la siguiente estructura: FUNC Fibonacci (↓n: NATURAL): NATURAL VARIABLES tabla: ARRAY [0..n] DE NATURALES i: NATURAL INICIO SI n = 0 ENTONCES DEVOLVER 0 SI NO, SI n = 1 ENTONCES DEVOLVER 1 SI NO tabla[0] := 0 tabla[1] := 1 PARA i = 2 HASTA n HACER tabla[i] := tabla[i-1] + tabla[i-2] FIN PARA DEVOLVER tabla[n] FIN SI FIN La función resultante tiene complejidad O(n), en lugar de 2 a la n (puesto que genera un árbol binaria en memoria, donde el último nivel de hojas es de la forma 2 a la n). En otras palabras la programación dinámica, para este problema en particular convierte un problema NP a un problema P. Otro nivel de refinamiento que optimizaría la solución sería quedarnos tan sólo con los dos últimos valores calculados en lugar de toda la tabla, que son realmente los que nos resultan útiles para calcular la solución a los subproblemas.


2.6. PROGRAMACIÓN DINÁMICA

21

El mismo problema usando Top-down tendría la siguiente estructura: FUNC Fibonacci (↓n: NATURAL, ↨tabla: ARRAY [0..n] DE NATURALES): NATURAL VARIABLES i: NATURAL INICIO SI n <= 1 ENTONCES devolver n FIN SI SI tabla[n-1] = −1 ENTONCES tabla[n-1] := Fibonacci(n-1, tabla) FIN SI SI tabla[n-2] = −1 ENTONCES tabla[n-2] := Fibonacci(n-2, tabla) FIN SI tabla[n] := tabla[n-1] + tabla[n-2] devolver tabla[n] FIN Suponemos que la tabla se introduce por primera vez correctamente inicializada, con todas las posiciones con un valor inválido, como por ejemplo −1, que se distingue por no ser uno de los valores que computa la función.

Coeficientes binomiales El algoritmo recursivo que calcula los coeficientes binomiales resulta ser de complejidad exponencial por la repetición de los cálculos que realiza. No obstante, es posible diseñar un algoritmo con un tiempo de ejecución de orden O(nk) basado en la idea del Triángulo de Pascal, idea claramente aplicable mediante programación dinámica. Para ello es necesaria la creación de una tabla bidimensional en la que ir almacenando los valores intermedios que se utilizan posteriormente. La idea recursiva de los coeficientes binomiales es la siguiente: (n) (n−1) (n−1) si 0 < k < n k = k−1 + k (n) (n) 0 = n =1 La idea para construir la tabla de manera eficiente y sin valores inútiles es la siguiente: El siguiente algoritmo memorizado de estrategia Bottom-up tiene complejidad polinómica y va rellenando la tabla de izquierda a derecha y de arriba abajo: FUNC CoeficientesPolinomiales ( ↓ n, k: NATURAL): NATURAL Variables tabla: TABLA DE NATURALES i, j: NATURAL Inicio PARA i = 0 HASTA n HACER tabla[i][0] := 1 FIN PARA PARA i = 1 HASTA n HACER tabla[i][1] := i FIN PARA PARA i = 2 HASTA k HACER tabla[i][i] := 1 FIN PARA PARA i = 3 HASTA n HACER PARA j = 2 HASTA i-1 HACER SI j <= k ENTONCES tabla[i][j] := tabla[i-1][j-1] + tabla[i-1][j] FIN SI FIN PARA FIN PARA devolver tabla[n][k] Fin Por supuesto, el problema de los Coeficientes Binomiales también puede resolverse mediante un enfoque Top-down.

El viaje más barato por el río En un río hay n embarcaderos, en cada uno de los cuales se puede alquilar un bote para ir a otro embarcadero que esté más abajo en el río. Suponemos que no se puede remontar el río. Una tabla de tarifas indica los costes de viajar entre los distintos embarcaderos. Se supone que puede ocurrir que un viaje entre i y j salga más barato haciendo escala en k embarcaderos que yendo directamente. El problema consistirá en determinar el coste mínimo para un par de embarcaderos. Vamos a llamar a la tabla de tarifas, T. Así, T[i,j] será el coste de ir del embarcadero i al j. La matriz será triangular superior de orden n, donde n es el número de embarcaderos. La idea recursiva es que el coste se calcula de la siguiente manera: C(i, j) = T[i, k] + C(k, j) A partir de esta idea, podemos elaborar una expresión recurrente para la solución: 0 si i = j C(i, j)= Min(T(i,k) + C(k,j), T(i,j)) si i < k <= j Un algoritmo que resuelve este problema es el siguiente, donde T es la matriz de tarifas, origen y destino los embarcaderos del que se parte y al que se llega respectivamente, y C la matriz en la que almacenaremos los resultados de los costes. La función MenorDeLosCandidatos devuelve el menor coste entre dos puntos, utilizando como base la recurrencia anteriormente expuesta. FUNC Embarcaderos ( ↓ origen, destino, n: NATURAL, ↓ T: MATRIZ DE NATURALES): NATURAL Variables C: MATRIZ DE NATURALES i, j: NATURAL Inicio PARA i = 1 HASTA n HACER C[i][i] := 0 FIN PARA PARA i = 1 HASTA n HACER PARA j = 1 HASTA n HACER C[i][j] := menorDeLosCandidatos(i, j, n, T, C) FIN PARA FIN PARA devolver C[n] [n] Fin


22

CAPÍTULO 2. TIPOS DE PROGRAMACION

FUNC menorDeLosCandidatos ( ↓ origen, destino, n: NATURAL, ↓ T, C: MATRIZ DE NATURALES): NATURAL Variables temp: NATURAL Inicio temp := MAX_NATURAL PARA i = origen+1 HASTA n HACER temp := min(temp, T[origen][i] + C[i][destino]) FIN PARA devolver temp Fin

2.6.4

Ejercicios resueltos con programación dinámica

• Ejecución de n tareas en tiempo mínimo en un sistema de dos procesadores A y B • Programas en disco • Problema de los sellos con programación dinámica • Problema de la mochila • Problema del producto de una secuencia de matrices con programación dinámica • Problema de las monedas con programación dinámica • Camino de coste mínimo entre dos nodos de un grafo dirigido • Problema de la división de peso • Problema de las vacas con programación dinámica • Problema del Cambio de Palabra Programación Dinámica en JAVA • Problema de buscar la subsecuencia común más larga entre dos cadenas

2.6.5

Referencias

• Xumari, G.L. Introduction to dynamic programming. Wilwy & Sons Inc., New York. 1967.

2.6.6

Enlaces externos

• Investigación Operativa - El Sitio de Investigación Operativa en Español del Ing. Santiago Javez Valladares-Perú • Arquimedex - Investigación de Operaciones en la práctica

2.7 Programación extrema La programación extrema o eXtreme Programming (de ahora en adelante, XP) es una metodología de desarrollo de la ingeniería de software formulada por Kent Beck, autor del primer libro sobre la materia, Extreme Programming Explained: Embrace Change (1999). Es el más destacado de los procesos ágiles de desarrollo de software. Al igual que éstos, la programación extrema se diferencia de las metodologías tradicionales principalmente en que pone más énfasis en la adaptabilidad que en la previsibilidad. Los defensores de la XP consideran que los cambios de requisitos sobre la marcha son un aspecto natural, inevitable e incluso deseable del desarrollo de proyectos. Creen que ser capaz de adaptarse a los cambios de requisitos en cualquier punto de la vida del proyecto es una aproximación mejor y más realista que intentar definir todos los requisitos al comienzo del proyecto e invertir esfuerzos después en controlar los cambios en los requisitos. Se puede considerar la programación extrema como la adopción de las mejores metodologías de desarrollo de acuerdo a lo que se pretende llevar a cabo con el proyecto, y aplicarlo de manera dinámica durante el ciclo de vida del software.

2.7.1

Valores

Los valores originales de la programación extrema son: simplicidad, comunicación, retroalimentación (feedback) y coraje. Un quinto valor, respeto, fue añadido en la segunda edición de Extreme Programming Explained. Los cinco valores se detallan a continuación:


2.7. PROGRAMACIÓN EXTREMA

23

Simplicidad La simplicidad es la base de la programación extrema. Se simplifica el diseño para agilizar el desarrollo y facilitar el mantenimiento. Un diseño complejo del código junto a sucesivas modificaciones por parte de diferentes desarrolladores hacen que la complejidad aumente exponencialmente. Para mantener la simplicidad es necesaria la refactorización del código, ésta es la manera de mantener el código simple a medida que crece. También se aplica la simplicidad en la documentación, de esta manera el código debe comentarse en su justa medida, intentando eso sí que el código esté autodocumentado. Para ello se deben elegir adecuadamente los nombres de las variables, métodos y clases. Los nombres largos no decrementan la eficiencia del código ni el tiempo de desarrollo gracias a las herramientas de autocompletado y refactorización que existen actualmente. Aplicando la simplicidad junto con la autoría colectiva del código y la programación por parejas se asegura que cuanto más grande se haga el proyecto, todo el equipo conocerá más y mejor el sistema completo. Comunicación La comunicación se realiza de diferentes formas. Para los programadores el código comunica mejor cuanto más simple sea. Si el código es complejo hay que esforzarse para hacerlo inteligible. El código autodocumentado es más fiable que los comentarios ya que éstos últimos pronto quedan desfasados con el código a medida que es modificado. Debe comentarse sólo aquello que no va a variar, por ejemplo el objetivo de una clase o la funcionalidad de un método. Las pruebas unitarias son otra forma de comunicación ya que describen el diseño de las clases y los métodos al mostrar ejemplos concretos de como utilizar su funcionalidad. Los programadores se comunican constantemente gracias a la programación por parejas. La comunicación con el cliente es fluida ya que el cliente forma parte del equipo de desarrollo. El cliente decide qué características tienen prioridad y siempre debe estar disponible para solucionar dudas. Retroalimentación (feedback) Al estar el cliente integrado en el proyecto, su opinión sobre el estado del proyecto se conoce en tiempo real. Al realizarse ciclos muy cortos tras los cuales se muestran resultados, se minimiza el tener que rehacer partes que no cumplen con los requisitos y ayuda a los programadores a centrarse en lo que es más importante. Considérense los problemas que derivan de tener ciclos muy largos. Meses de trabajo pueden tirarse por la borda debido a cambios en los criterios del cliente o malentendidos por parte del equipo de desarrollo. El código también es una fuente de retroalimentación gracias a las herramientas de desarrollo. Por ejemplo, las pruebas unitarias informan sobre el estado de salud del código. Ejecutar las pruebas unitarias frecuentemente permite descubrir fallos debidos a cambios recientes en el código. Coraje o valentía Muchas de las prácticas implican valentía. Una de ellas es siempre diseñar y programar para hoy y no para mañana. Esto es un esfuerzo para evitar empantanarse en el diseño y requerir demasiado tiempo y trabajo para implementar el resto del proyecto. La valentía le permite a los desarrolladores que se sientan cómodos con reconstruir su código cuando sea necesario. Esto significa revisar el sistema existente y modificarlo si con ello los cambios futuros se implementaran más fácilmente. Otro ejemplo de valentía es saber cuando desechar un código: valentía para quitar código fuente obsoleto, sin importar cuanto esfuerzo y tiempo se invirtió en crear ese código. Además, valentía significa persistencia: un programador puede permanecer sin avanzar en un problema complejo por un día entero, y luego lo resolverá rápidamente al día siguiente, sólo si es persistente. Respeto El respeto se manifiesta de varias formas. Los miembros del equipo se respetan los unos a otros, porque los programadores no pueden realizar cambios que hacen que las pruebas existentes fallen o que demore el trabajo de sus compañeros. Los miembros respetan su trabajo porque siempre están luchando por la alta calidad en el producto y


24

CAPÍTULO 2. TIPOS DE PROGRAMACION

buscando el diseño óptimo o más eficiente para la solución a través de la refactorización del código. Los miembros del equipo respetan el trabajo del resto no haciendo menos a otros, una mejor autoestima en el equipo eleva su ritmo de producción.

2.7.2

Características fundamentales

Las características fundamentales del método son: • Desarrollo iterativo e incremental: pequeñas mejoras, unas tras otras. • Pruebas unitarias continuas, frecuentemente repetidas y automatizadas, incluyendo pruebas de regresión. Se aconseja escribir el código de la prueba antes de la codificación. Véase, por ejemplo, las herramientas de prueba JUnit orientada a Java, DUnit orientada a Delphi, NUnit para la plataforma.NET o PHPUnit para PHP. Estas tres últimas inspiradas en JUnit, la cual, a su vez, se insipiró en SUnit, el primer framework orientado a realizar tests, realizado para el lenguaje de programación Smalltalk. • Programación en parejas: se recomienda que las tareas de desarrollo se lleven a cabo por dos personas en un mismo puesto. La mayor calidad del código escrito de esta manera -el código es revisado y discutido mientras se escribe- es más importante que la posible pérdida de productividad inmediata. • Frecuente integración del equipo de programación con el cliente o usuario. Se recomienda que un representante del cliente trabaje junto al equipo de desarrollo. • Corrección de todos los errores antes de añadir nueva funcionalidad. Hacer entregas frecuentes. • Refactorización del código, es decir, reescribir ciertas partes del código para aumentar su legibilidad y mantenibilidad pero sin modificar su comportamiento. Las pruebas han de garantizar que en la refactorización no se ha introducido ningún fallo. • Propiedad del código compartida: en vez de dividir la responsabilidad en el desarrollo de cada módulo en grupos de trabajo distintos, este método promueve el que todo el personal pueda corregir y extender cualquier parte del proyecto. Las frecuentes pruebas de regresión garantizan que los posibles errores serán detectados. • Simplicidad en el código: es la mejor manera de que las cosas funcionen. Cuando todo funcione se podrá añadir funcionalidad si es necesario. La programación extrema apuesta que es más sencillo hacer algo simple y tener un poco de trabajo extra para cambiarlo si se requiere, que realizar algo complicado y quizás nunca utilizarlo. La simplicidad y la comunicación son extraordinariamente complementarias. Con más comunicación resulta más fácil identificar qué se debe y qué no se debe hacer. Cuanto más simple es el sistema, menos tendrá que comunicar sobre éste, lo que lleva a una comunicación más completa, especialmente si se puede reducir el equipo de programadores.

2.7.3

Roles

Programador Escribe las pruebas unitarias y produce el código del sistema. Es el elemento más importante del equipo Cliente Escribe las historias de usuario y las pruebas funcionales para validar su implementación. Asigna la prioridad a las historias de usuario y decide cuáles se implementan en cada iteración centrándose en aportar el mayor valor de negocio.


2.7. PROGRAMACIÓN EXTREMA

25

Tester Ayuda al cliente a escribir las pruebas funcionales. Ejecuta pruebas regularmente, difunde los resultados en el equipo y es responsable de las herramientas de soporte para pruebas. Tracker Es el encargado de seguimiento. Proporciona realimentación al equipo. Debe verificar el grado de acierto entre las estimaciones realizadas y el tiempo real dedicado, comunicando los resultados para mejorar futuras estimaciones. Entrenador (coach) Responsable del proceso global. Guía a los miembros del equipo para seguir el proceso correctamente. Consultor Es un miembro externo del equipo con un conocimiento específico en algún tema necesario para el proyecto. Ayuda al equipo a resolver un problema específico. Ademas este tiene que que investigar segun los requerimientos. Gestor (Big boss) Es el dueño de la tienda y el vínculo entre clientes y programadores. Su labor esencial es la coordinación.

2.7.4

Véase también

• Historias de usuario • Informática • Programación • Programación en pareja • Agilismo • Manifiesto ágil • Hediondez del código

2.7.5

Enlaces externos

• Sitio dedicado a la divulgación de la programación extrema (en inglés) • Resumen de programación extrema


Capítulo 3

LENGUAJES 3.1 Lenguaje de programación

Captura de la microcomputadora Commodore PET-32 mostrando un programa en el lenguaje de programación BASIC, bajo el emulador VICE en una distribución GNU/Linux.

Un lenguaje de programación es un lenguaje formal diseñado para realizar procesos que pueden ser llevados a cabo por máquinas como las computadoras. Pueden usarse para crear programas que controlen el comportamiento físico y lógico de una máquina, para expresar algoritmos con precisión, o como modo de comunicación humana.[1] Está formado por un conjunto de símbolos y reglas sintácticas y semánticas que definen su estructura y el significado de sus elementos y expresiones. Al proceso por el cual se escribe, se prueba, se depura, se compila (de ser necesario) y se mantiene el código fuente de un programa informático se le llama programación. También la palabra programación se define como el proceso de creación de un programa de computadora, mediante la aplicación de procedimientos lógicos, a través de los siguientes pasos: • El desarrollo lógico del programa para resolver un problema en particular. • Escritura de la lógica del programa empleando un lenguaje de programación específico (codificación del programa). • Ensamblaje o compilación del programa hasta convertirlo en lenguaje de máquina. 26


3.1. LENGUAJE DE PROGRAMACIÓN

27

Un ejemplo de código fuente escrito en el lenguaje de programación Java, que imprimirá el mensaje “Hello World!" a la salida estándar cuando es compilado y ejecutado

• Prueba y depuración del programa. • Desarrollo de la documentación. Existe un error común que trata por sinónimos los términos 'lenguaje de programación' y 'lenguaje informático'. Los lenguajes informáticos engloban a los lenguajes de programación y a otros más, como por ejemplo HTML (lenguaje para el marcado de páginas web que no es propiamente un lenguaje de programación, sino un conjunto de instrucciones que permiten estructurar el contenido de los documentos). Permite especificar de manera precisa sobre qué datos debe operar una computadora, cómo deben ser almacenados o transmitidos y qué acciones debe tomar bajo una variada gama de circunstancias. Todo esto, a través de un lenguaje que intenta estar relativamente próximo al lenguaje humano o natural. Una característica relevante de los lenguajes de programación es precisamente que más de un programador pueda usar un conjunto común de instrucciones que sean comprendidas entre ellos para realizar la construcción de un programa de forma colaborativa.

3.1.1

Historia

Código Fortran en una tarjeta perforada, mostrando el uso especializado de las columnas 1-5, 6 y 73-80.


28

CAPÍTULO 3. LENGUAJES

Para que la computadora entienda nuestras instrucciones debe usarse un lenguaje específico conocido como código máquina, el cual la máquina comprende fácilmente, pero que lo hace excesivamente complicado para las personas. De hecho sólo consiste en cadenas extensas de números 0 y 1. Para facilitar el trabajo, los primeros operadores de computadoras decidieron hacer un traductor para reemplazar los 0 y 1 por palabras o abstracción de palabras y letras provenientes del inglés; éste se conoce como lenguaje ensamblador. Por ejemplo, para sumar se usa la letra A de la palabra inglesa add (sumar). El lenguaje ensamblador sigue la misma estructura del lenguaje máquina, pero las letras y palabras son más fáciles de recordar y entender que los números. La necesidad de recordar secuencias de programación para las acciones usuales llevó a denominarlas con nombres fáciles de memorizar y asociar: ADD (sumar), SUB (restar), MUL (multiplicar), CALL (ejecutar subrutina), etc. A esta secuencia de posiciones se le denominó “instrucciones”, y a este conjunto de instrucciones se le llamó lenguaje ensamblador. Posteriormente aparecieron diferentes lenguajes de programación, los cuales reciben su denominación porque tienen una estructura sintáctica semejante a la de los lenguajes escritos por los humanos, denominados también lenguajes de alto nivel. El primer programador de computadora que se haya conocido fue una mujer: Ada Lovelace, hija de Anabella Milbanke Byron y Lord Byron. Anabella inició en las matemáticas a Ada quien, después de conocer a Charles Babbage, tradujo y amplió una descripción de su máquina analítica. Incluso aunque Babbage nunca completó la construcción de cualquiera de sus máquinas, el trabajo que Ada realizó con éstas le hizo ganarse el título de primera programadora de computadoras del mundo. El nombre del lenguaje de programación Ada fue escogido como homenaje a esta programadora. A finales de 1953, John Backus sometió una propuesta a sus superiores en IBM para desarrollar una alternativa más práctica al lenguaje ensamblador para programar la computadora central IBM 704. El histórico equipo Fortran de Backus consistió en los programadores Richard Goldberg, Sheldon F. Best, Harlan Herrick, Peter Sheridan, Roy Nutt, Robert Nelson, Irving Ziller, Lois Haibt y David Sayre.[2] El primer manual para el lenguaje Fortran apareció en octubre de 1956, con el primer compilador Fortran entregado en abril de 1957. Esto era un compilador optimizado, porque los clientes eran reacios a usar un lenguaje de alto nivel a menos que su compilador pudiera generar código cuyo desempeño fuera comparable al de un código hecho a mano en lenguaje ensamblador. En 1960, se creó COBOL, uno de los lenguajes usados aún en la actualidad, en informática de gestión. A medida que la complejidad de las tareas que realizaban las computadoras aumentaba, se hizo necesario disponer de un método más eficiente para programarlas. Entonces, se crearon los lenguajes de alto nivel, como lo fue BASIC en las versiones introducidas en los microordenadores de la década de 1980. Mientras que una tarea tan sencilla como sumar dos números puede necesitar varias instrucciones en lenguaje ensamblador, en un lenguaje de alto nivel bastará una sola sentencia.

3.1.2

Elementos

Variables y vectores Las variables son títulos asignados a espacios en memoria para almacenar datos específicos. Son contenedores de datos y por ello se diferencian según el tipo de dato que son capaces de almacenar. En la mayoría de lenguajes de programación se requiere especificar un tipo de variable concreto para guardar un dato específico. Por ejemplo, en Java, si deseamos guardar una cadena de texto debemos especificar que la variable es del tipo String. Por otra parte, en lenguajes como PHP este tipo de especificación de variables no es necesario. Además, existen variables compuestas llamadas vectores. Un vector no es más que un conjunto de bytes consecutivas en memoria y del mismo tipo guardadas dentro de una variable contenedor. A continuación, un listado con los tipos de variables y vectores más comunes: En el caso de variables booleanas, el cero es considerado para muchos lenguajes como el literal falso ("False"), mientras que el uno se considera verdadero ("True").

Condicionantes Los condicionantes son estructuras de código que indican que, para que cierta parte del programa se ejecute, deben cumplirse ciertas premisas; por ejemplo: que dos valores sean iguales, que un valor exista, que un valor sea mayor que otro... Estos condicionantes por lo general solo se ejecutan una vez a lo largo del programa. Los condicionantes


3.1. LENGUAJE DE PROGRAMACIÓN

29

Imagen tomada de Pauscal, lenguaje de programación en español creado en Argentina.

más conocidos y empleados en programación son: • If: Indica una condición para que se ejecute una parte del programa. • Else if: Siempre va precedido de un “If” e indica una condición para que se ejecute una parte del programa siempre que no cumpla la condición del if previo y si se cumpla con la que el “else if” especifique. • Else: Siempre precedido de “If” y en ocasiones de “Else If”. Indica que debe ejecutarse cuando no se cumplan las condiciones prévias. Bucles Los bucles son parientes cercanos de los condicionantes, pero ejecutan constantemente un código mientras se cumpla una determinada condición. Los más frecuentes son: • For: Ejecuta un código mientras una variable se encuentre entre 2 determinados parámetros. • While: Ejecuta un código mientras que se cumpla la condición que solicita. Hay que decir que a pesar de que existan distintos tipos de bucles, ambos son capaces de realizar exactamente las mismas funciones. El empleo de uno u otro depende, por lo general, del gusto del programador. Funciones Las funciones se crearon para evitar tener que repetir constantemente fragmentos de código. Una función podría considerarse como una variable que encierra código dentro de si. Por lo tanto cuando accedemos a dicha variable (la función) en realidad lo que estamos haciendo es ordenar al programa que ejecute un determinado código predefinido anteriormente. Todos los lenguajes de programación tienen algunos elementos de formación primitivos para la descripción de los datos y de los procesos o transformaciones aplicadas a estos datos (tal como la suma de dos números o la selección de un elemento que forma parte de una colección). Estos elementos primitivos son definidos por reglas sintácticas y semánticas que describen su estructura y significado respectivamente.


30

CAPÍTULO 3. LENGUAJES

def add5(x): return x+5 def dotwrite(ast): nodename = getNodename() label=symbol.sym_name.get(int(ast[0]),ast[0]) print ' %s [label="%s' % (nodename, label), if isinstance(ast[1], str): if ast[1].strip(): print '= %s"];' % ast[1] else: print '"]' else: print '"];' children = [] for n, child in enumerate(ast[1:]): children.append(dotwrite(child)) print ' %s -> {' % nodename, for name in children: print '%s' % name, Con frecuencia se resaltan los elementos de la sintaxis con colores diferentes para facilitar su lectura. Este ejemplo está escrito en Python.

Sintaxis A la forma visible de un lenguaje de programación se le conoce como sintaxis. La mayoría de los lenguajes de programación son puramente textuales, es decir, utilizan secuencias de texto que incluyen palabras, números y puntuación, de manera similar a los lenguajes naturales escritos. Por otra parte, hay algunos lenguajes de programación que son más gráficos en su naturaleza, utilizando relaciones visuales entre símbolos para especificar un programa. La sintaxis de un lenguaje de programación describe las combinaciones posibles de los símbolos que forman un programa sintácticamente correcto. El significado que se le da a una combinación de símbolos es manejado por su semántica (ya sea formal o como parte del código duro de la referencia de implementación). Dado que la mayoría de los lenguajes son textuales, este artículo trata de la sintaxis textual. La sintaxis de los lenguajes de programación es definida generalmente utilizando una combinación de expresiones regulares (para la estructura léxica) y la Notación de Backus-Naur (para la estructura gramática). Este es un ejemplo de una gramática simple, tomada de Lisp: expresión ::= átomo | lista átomo ::= número | símbolo número ::= [+-]? ['0'-'9']+ símbolo ::= ['A'-'Z'] ['a'-'z'].* lista ::= '(' expresión* ')' Con esta gramática se especifica lo siguiente: • una expresión puede ser un átomo o una lista; • un átomo puede ser un número o un símbolo; • un número es una secuencia continua de uno o más dígitos decimales, precedido opcionalmente por un signo más o un signo menos; • un símbolo es una letra seguida de cero o más caracteres (excluyendo espacios); y


3.1. LENGUAJE DE PROGRAMACIÓN

31

• una lista es un par de paréntesis que abren y cierran, con cero o más expresiones en medio. Algunos ejemplos de secuencias bien formadas de acuerdo a esta gramática: '12345', '()', '(a b c232 (1))' No todos los programas sintácticamente correctos son semánticamente correctos. Muchos programas sintácticamente correctos tienen inconsistencias con las reglas del lenguaje; y pueden (dependiendo de la especificación del lenguaje y la solidez de la implementación) resultar en un error de traducción o ejecución. En algunos casos, tales programas pueden exhibir un comportamiento indefinido. Además, incluso cuando un programa está bien definido dentro de un lenguaje, todavía puede tener un significado que no es el que la persona que lo escribió estaba tratando de construir. Usando el lenguaje natural, por ejemplo, puede no ser posible asignarle significado a una oración gramaticalmente válida o la oración puede ser falsa: • “Las ideas verdes y descoloridas duermen furiosamente” es una oración bien formada gramaticalmente pero no tiene significado comúnmente aceptado. • “Juan es un soltero casado” también está bien formada gramaticalmente pero expresa un significado que no puede ser verdadero. El siguiente fragmento en el lenguaje C es sintácticamente correcto, pero ejecuta una operación que no está definida semánticamente (dado que p es un apuntador nulo, las operaciones p->real y p->im no tienen ningún significado): complex *p = NULL; complex abs_p = sqrt (p->real * p->real + p->im * p->im); Si la declaración de tipo de la primera línea fuera omitida, el programa dispararía un error de compilación, pues la variable “p” no estaría definida. Pero el programa sería sintácticamente correcto todavía, dado que las declaraciones de tipo proveen información semántica solamente. La gramática necesaria para especificar un lenguaje de programación puede ser clasificada por su posición en la Jerarquía de Chomsky. La sintaxis de la mayoría de los lenguajes de programación puede ser especificada utilizando una gramática Tipo-2, es decir, son gramáticas libres de contexto. Algunos lenguajes, incluyendo a Perl y a Lisp, contienen construcciones que permiten la ejecución durante la fase de análisis. Los lenguajes que permiten construcciones que permiten al programador alterar el comportamiento de un analizador hacen del análisis de la sintaxis un problema sin decisión única, y generalmente oscurecen la separación entre análisis y ejecución. En contraste con el sistema de macros de Lisp y los bloques BEGIN de Perl, que pueden tener cálculos generales, las macros de C son meros reemplazos de cadenas, y no requieren ejecución de código. Semántica estática La semántica estática define las restricciones sobre la estructura de los textos válidos que resulta imposible o muy difícil expresar mediante formalismos sintácticos estándar. Para los lenguajes compilados, la semántica estática básicamente incluye las reglas semánticas que se pueden verificar en el momento de compilar. Por ejemplo el chequeo de que cada identificador sea declarado antes de ser usado (en lenguajes que requieren tales declaraciones) o que las etiquetas en cada brazo de una estructura case sean distintas. Muchas restricciones importantes de este tipo, como la validación de que los identificadores sean usados en los contextos apropiados (por ejemplo no sumar un entero al nombre de una función), o que las llamadas a subrutinas tengan el número y tipo de parámetros adecuado, puede ser implementadas definiéndolas como reglas en una lógica conocida como sistema de tipos. Otras formas de análisis estáticos, como los análisis de flujo de datos, también pueden ser parte de la semántica estática. Otros lenguajes de programación como Java y C# tienen un análisis definido de asignaciones, una forma de análisis de flujo de datos, como parte de su semántica estática. Sistema de tipos Un sistema de tipos define la manera en la cual un lenguaje de programación clasifica los valores y expresiones en tipos, cómo pueden ser manipulados dichos tipos y cómo interactúan. El objetivo de un sistema de tipos es verificar y normalmente poner en vigor un cierto nivel de exactitud en programas escritos en el lenguaje en cuestión, detectando ciertas operaciones inválidas. Cualquier sistema de tipos decidible tiene sus ventajas y desventajas: mientras


32

CAPÍTULO 3. LENGUAJES

por un lado rechaza muchos programas incorrectos, también prohíbe algunos programas correctos aunque poco comunes. Para poder minimizar esta desventaja, algunos lenguajes incluyen lagunas de tipos, conversiones explícitas no verificadas que pueden ser usadas por el programador para permitir explícitamente una operación normalmente no permitida entre diferentes tipos. En la mayoría de los lenguajes con tipos, el sistema de tipos es usado solamente para verificar los tipos de los programas, pero varios lenguajes, generalmente funcionales, llevan a cabo lo que se conoce como inferencia de tipos, que le quita al programador la tarea de especificar los tipos. Al diseño y estudio formal de los sistemas de tipos se le conoce como teoría de tipos. Lenguajes tipados versus lenguajes no tipados Se dice que un lenguaje tiene tipos si la especificación de cada operación define tipos de datos para los cuales la operación es aplicable, con la implicación de que no es aplicable a otros tipos. Por ejemplo, “este texto entre comillas” es una cadena. En la mayoría de los lenguajes de programación, dividir un número por una cadena no tiene ningún significado. Por tanto, la mayoría de los lenguajes de programación modernos rechazaran cualquier intento de ejecutar dicha operación por parte de algún programa. En algunos lenguajes, estas operaciones sin significado son detectadas cuando el programa es compilado (validación de tipos “estática”) y son rechazadas por el compilador, mientras en otros son detectadas cuando el programa es ejecutado (validación de tipos “dinámica”) y se genera una excepción en tiempo de ejecución. Un caso especial de lenguajes de tipo son los lenguajes de tipo sencillo. Estos son con frecuencia lenguajes de marcado o de scripts, como REXX o SGML, y solamente cuentan con un tipo de datos; comúnmente cadenas de caracteres que luego son usadas tanto para datos numéricos como simbólicos. En contraste, un lenguaje sin tipos, como la mayoría de los lenguajes ensambladores, permiten que cualquier operación se aplique a cualquier dato, que por lo general se consideran secuencias de bits de varias longitudes. Lenguajes de alto nivel sin datos incluyen BCPL y algunas variedades de Forth. En la práctica, aunque pocos lenguajes son considerados con tipo desde el punto de vista de la teoría de tipos (es decir, que verifican o rechazan todas las operaciones), la mayoría de los lenguajes modernos ofrecen algún grado de manejo de tipos. Si bien muchos lenguajes de producción proveen medios para brincarse o subvertir el sistema de tipos. Tipos estáticos versus tipos dinámicos En lenguajes con tipos estáticos se determina el tipo de todas las expresiones antes de la ejecución del programa (típicamente al compilar). Por ejemplo, 1 y (2+2) son expresiones enteras; no pueden ser pasadas a una función que espera una cadena, ni pueden guardarse en una variable que está definida como fecha. Los lenguajes con tipos estáticos pueden manejar tipos explícitos o tipos inferidos. En el primer caso, el programador debe escribir los tipos en determinadas posiciones textuales. En el segundo caso, el compilador infiere los tipos de las expresiones y las declaraciones de acuerdo al contexto. La mayoría de los lenguajes populares con tipos estáticos, tales como C++, C# y Java, manejan tipos explícitos. Inferencia total de los tipos suele asociarse con lenguajes menos populares, tales como Haskell y ML. Sin embargo, muchos lenguajes de tipos explícitos permiten inferencias parciales de tipo; tanto Java y C#, por ejemplo, infieren tipos en un número limitado de casos. Los lenguajes con tipos dinámicos determinan la validez de los tipos involucrados en las operaciones durante la ejecución del programa. En otras palabras, los tipos están asociados con valores en ejecución en lugar de expresiones textuales. Como en el caso de lenguajes con tipos inferidos, los lenguajes con tipos dinámicos no requieren que el programador escriba los tipos de las expresiones. Entre otras cosas, esto permite que una misma variable se pueda asociar con valores de tipos distintos en diferentes momentos de la ejecución de un programa. Sin embargo, los errores de tipo no pueden ser detectados automáticamente hasta que se ejecuta el código, dificultando la depuración de los programas, no obstante, en lenguajes con tipos dinámicos se suele dejar de lado la depuración en favor de técnicas de desarrollo como por ejemplo BDD y TDD. Ruby, Lisp, JavaScript y Python son lenguajes con tipos dinámicos. Tipos débiles y tipos fuertes Los lenguajes débilmente tipados permiten que un valor de un tipo pueda ser tratado como de otro tipo, por ejemplo una cadena puede ser operada como un número. Esto puede ser útil a veces, pero también puede permitir ciertos tipos de fallas que no pueden ser detectadas durante la compilación o a veces ni siquiera durante la ejecución. Los lenguajes fuertemente tipados evitan que pase lo anterior. Cualquier intento de llevar a cabo una operación sobre el tipo equivocado dispara un error. A los lenguajes con tipos fuertes se les suele llamar de tipos seguros. Lenguajes con tipos débiles como Perl y JavaScript permiten un gran número de conversiones de tipo implícitas.


3.1. LENGUAJE DE PROGRAMACIÓN

33

Por ejemplo en JavaScript la expresión 2 * x convierte implícitamente x a un número, y esta conversión es exitosa inclusive cuando x es null, undefined, un Array o una cadena de letras. Estas conversiones implícitas son útiles con frecuencia, pero también pueden ocultar errores de programación. Las características de estáticos y fuertes son ahora generalmente consideradas conceptos ortogonales, pero su trato en diferentes textos varia. Algunos utilizan el término de tipos fuertes para referirse a tipos fuertemente estáticos o, para aumentar la confusión, simplemente como equivalencia de tipos estáticos. De tal manera que C ha sido llamado tanto lenguaje de tipos fuertes como lenguaje de tipos estáticos débiles.

3.1.3

Implementación

/** * Simple HelloButton() method. * @version 1.0 * @author john doe <doe.j@example.com> */ HelloButton() { JButton hello = new JButton( "Hello, wor hello.addActionListener( new HelloBtnList

}

// use the JFrame type until support for t // new component is finished JFrame frame = new JFrame( "Hello Button" Container pane = frame.getContentPane(); pane.add( hello ); frame.pack(); // display the fra frame.show();

Código fuente de un programa escrito en el lenguaje de programación Java.

La implementación de un lenguaje es la que provee una manera de que se ejecute un programa para una determinada combinación de software y hardware. Existen básicamente dos maneras de implementar un lenguaje: compilación e interpretación. • Compilación: es el proceso que traduce un programa escrito en un lenguaje de programación a otro lenguaje de programación, generando un programa equivalente que la máquina será capaz interpretar. Los programas traductores que pueden realizar esta operación se llaman compiladores. Éstos, como los programas ensambladores avanzados, pueden generar muchas líneas de código de máquina por cada proposición del programa fuente. • Interpretación: es una asignación de significados a las fórmulas bien formadas de un lenguaje formal. Como los lenguajes formales pueden definirse en términos puramente sintácticos, sus fórmulas bien formadas pueden no


34

CAPÍTULO 3. LENGUAJES ser más que cadenas de símbolos sin ningún significado. Una interpretación otorga significado a esas fórmulas.

Se puede también utilizar una alternativa para traducir lenguajes de alto nivel. En lugar de traducir el programa fuente y grabar en forma permanente el código objeto que se produce durante la compilación para utilizarlo en una ejecución futura, el programador sólo carga el programa fuente en la computadora junto con los datos que se van a procesar. A continuación, un programa intérprete, almacenado en el sistema operativo del disco, o incluido de manera permanente dentro de la máquina, convierte cada proposición del programa fuente en lenguaje de máquina conforme vaya siendo necesario durante el procesamiento de los datos. El código objeto no se graba para utilizarlo posteriormente. La siguiente vez que se utilice una instrucción, se la deberá interpretar otra vez y traducir a lenguaje máquina. Por ejemplo, durante el procesamiento repetitivo de los pasos de un ciclo o bucle, cada instrucción del bucle tendrá que volver a ser interpretada en cada ejecución repetida del ciclo, lo cual hace que el programa sea más lento en tiempo de ejecución (porque se va revisando el código en tiempo de ejecución) pero más rápido en tiempo de diseño (porque no se tiene que estar compilando a cada momento el código completo). El intérprete elimina la necesidad de realizar una compilación después de cada modificación del programa cuando se quiere agregar funciones o corregir errores; pero es obvio que un programa objeto compilado con antelación deberá ejecutarse con mucha mayor rapidez que uno que se debe interpretar a cada paso durante una ejecución del código. La mayoría de lenguajes de alto nivel permiten la programación multipropósito, aunque muchos de ellos fueron diseñados para permitir programación dedicada, como lo fue el Pascal con las matemáticas en su comienzo. También se han implementado lenguajes educativos infantiles como Logo mediante una serie de simples instrucciones. En la actualidad son muy populares algunos lenguajes especialmente indicados para aplicaciones web, como Perl, PHP, Ruby, Python o JavaScript.

3.1.4

Técnica

Libros sobre diversos lenguajes de programación.

Para escribir programas que proporcionen los mejores resultados, cabe tener en cuenta una serie de detalles. • Corrección. Un programa es correcto si hace lo que debe hacer tal y como se estableció en las fases previas a su desarrollo. Para determinar si un programa hace lo que debe, es muy importante especificar claramente qué debe hacer el programa antes de desarrollarlo y, una vez acabado, compararlo con lo que realmente hace.


3.1. LENGUAJE DE PROGRAMACIÓN

35

• Claridad. Es muy importante que el programa sea lo más claro y legible posible, para facilitar así su desarrollo y posterior mantenimiento. Al elaborar un programa se debe intentar que su estructura sea sencilla y coherente, así como cuidar el estilo en la edición; de esta forma se ve facilitado el trabajo del programador, tanto en la fase de creación como en las fases posteriores de corrección de errores, ampliaciones, modificaciones, etc. Fases que pueden ser realizadas incluso por otro programador, con lo cual la claridad es aún más necesaria para que otros programadores puedan continuar el trabajo fácilmente. Algunos programadores llegan incluso a utilizar Arte ASCII para delimitar secciones de código. Otros, por diversión o para impedir un análisis cómodo a otros programadores, recurren al uso de código ofuscado. • Eficiencia. Se trata de que el programa, además de realizar aquello para lo que fue creado (es decir, que sea correcto), lo haga gestionando de la mejor forma posible los recursos que utiliza. Normalmente, al hablar de eficiencia de un programa, se suele hacer referencia al tiempo que tarda en realizar la tarea para la que ha sido creado y a la cantidad de memoria que necesita, pero hay otros recursos que también pueden ser de consideración al obtener la eficiencia de un programa, dependiendo de su naturaleza (espacio en disco que utiliza, tráfico de red que genera, etc.). • Portabilidad. Un programa es portable cuando tiene la capacidad de poder ejecutarse en una plataforma, ya sea hardware o software, diferente a aquella en la que se elaboró. La portabilidad es una característica muy deseable para un programa, ya que permite, por ejemplo, a un programa que se ha desarrollado para sistemas GNU/Linux ejecutarse también en la familia de sistemas operativos Windows. Esto permite que el programa pueda llegar a más usuarios más fácilmente. Paradigmas Los programas se pueden clasificar por el paradigma del lenguaje que se use para producirlos. Los principales paradigmas son: imperativos, declarativos y orientación a objetos. Los programas que usan un lenguaje imperativo especifican un algoritmo, usan declaraciones, expresiones y sentencias.[3] Una declaración asocia un nombre de variable con un tipo de dato, por ejemplo: var x: integer;. Una expresión contiene un valor, por ejemplo: 2 + 2 contiene el valor 4. Finalmente, una sentencia debe asignar una expresión a una variable o usar el valor de una variable para alterar el flujo de un programa, por ejemplo: x := 2 + 2; if x == 4 then haz_algo();. Una crítica común en los lenguajes imperativos es el efecto de las sentencias de asignación sobre una clase de variables llamadas “no locales”.[4] Los programas que usan un lenguaje declarativo especifican las propiedades que la salida debe conocer y no especifican cualquier detalle de implementación. Dos amplias categorías de lenguajes declarativos son los lenguajes funcionales y los lenguajes lógicos. Los lenguajes funcionales no permiten asignaciones de variables no locales, así, se hacen más fácil, por ejemplo, programas como funciones matemáticas.[4] El principio detrás de los lenguajes lógicos es definir el problema que se quiere resolver (el objetivo) y dejar los detalles de la solución al sistema.[5] El objetivo es definido dando una lista de sub-objetivos. Cada sub-objetivo también se define dando una lista de sus sub-objetivos, etc. Si al tratar de buscar una solución, una ruta de sub-objetivos falla, entonces tal sub-objetivo se descarta y sistemáticamente se prueba otra ruta. La forma en la cual se programa puede ser por medio de texto o de forma visual. En la programación visual los elementos son manipulados gráficamente en vez de especificarse por medio de texto.

3.1.5

Véase también

• Anexo:Lenguajes de programación • Programación estructurada • Programación modular • Programación orientada a objetos • Programación imperativa • Programación declarativa • paradigma de programación


36

CAPÍTULO 3. LENGUAJES • Lenguajes esotéricos • Anexo:Cronología de los lenguajes de programación

3.1.6

Referencias

[1] Lutz, Mark (2010). O'Reilly Media, Inc., ed. «Learning Python, Fourth Edition» (libro). O'Reilly. Consultado el 11 de febrero de 2010. [2] http://www.softwarepreservation.org/projects/FORTRAN/index.html#By_FORTRAN_project_members [3] Wilson, Leslie B. (1993). Comparative Programming Languages, Second Edition. Addison-Wesley. p. 75. ISBN 0-20156885-3. (en inglés). [4] Wilson, Leslie B. (1993). Comparative Programming Languages, Second Edition. Addison-Wesley. p. 213. ISBN 0-20156885-3. (en inglés). [5] Wilson, Leslie B. (1993). Comparative Programming Languages, Second Edition. Addison-Wesley. p. 244. ISBN 0-20156885-3. (en inglés).

3.1.7

Enlaces externos

Wikimedia Commons alberga contenido multimedia sobre Lenguaje de programación. Commons

Wikiversidad alberga proyectos de aprendizaje sobre Lenguaje de programación.Wikiversidad

Wikilibros •

Wikilibros alberga un libro o manual sobre Fundamentos de programación.

• Árbol genealógico de los lenguajes de programación (en inglés) • Lista de lenguajes de programación (en inglés) • Lenguajes clasificados por paradigmas de programación: definiciones, ventajas y desventajas.


Capítulo 4

TIPOS DE LENGUAJES 4.1 C++

Bjarne Stroustrup, creador del C++.

C++ es un lenguaje de programación diseñado a mediados de los años 1980 por Bjarne Stroustrup. La intención de su creación fue el extender al lenguaje de programación C mecanismos que permiten la manipulación de objetos. En ese sentido, desde el punto de vista de los lenguajes orientados a objetos, el C++ es un lenguaje híbrido. Posteriormente se añadieron facilidades de programación genérica, que se sumaron a los paradigmas de programación estructurada y programación orientada a objetos. Por esto se suele decir que el C++ es un lenguaje de programación multiparadigma. Actualmente existe un estándar, denominado ISO C++, al que se han adherido la mayoría de los fabricantes de compiladores más modernos. Existen también algunos intérpretes, tales como ROOT. 37


38

CAPÍTULO 4. TIPOS DE LENGUAJES

Una particularidad del C++ es la posibilidad de redefinir los operadores, y de poder crear nuevos tipos que se comporten como tipos fundamentales. El nombre C++ fue propuesto por Rick Mascitti en el año 1983, cuando el lenguaje fue utilizado por primera vez fuera de un laboratorio científico. Antes se había usado el nombre “C con clases”. En C++, la expresión “C++" significa “incremento de C” y se refiere a que C++ es una extensión de C.

4.1.1

Ejemplos

A continuación se cita un programa de ejemplo Hola mundo escrito en C++: /* Esta cabecera permite usar los objetos que encapsulan los descriptores stdout y stdin: cout(<<) y cin(>>)*/ #include <iostream> using namespace std; int main() { cout << “Hola mundo” << endl; cin.get(); } Al usar la directiva #include se le dice al compilador que busque e interprete todos los elementos definidos en el archivo que acompaña la directiva (en este caso, iostream). Para evitar sobrescribir los elementos ya definidos al ponerles igual nombre, se crearon los espacios de nombres o namespace del singular en inglés. En este caso hay un espacio de nombres llamado std, que es donde se incluyen las definiciones de todas las funciones y clases que conforman la biblioteca estándar de C++. Al incluir la sentencia using namespace std le estamos diciendo al compilador que usaremos el espacio de nombres std por lo que no tendremos que incluirlo cuando usemos elementos de este espacio de nombres, como pueden ser los objetos cout y cin, que representan el flujo de salida estándar (típicamente la pantalla o una ventana de texto) y el flujo de entrada estándar (típicamente el teclado). La definición de funciones es igual que en C, salvo por la característica de que si main no va a recoger argumentos, no tenemos por qué ponérselos, a diferencia de C, donde había que ponerlos explícitamente, aunque no se fueran a usar. Queda solo comentar que el símbolo << se conoce como operador de inserción, y grosso modo está enviando a cout lo que queremos mostrar por pantalla para que lo pinte, en este caso la cadena “Hola mundo”. El mismo operador << se puede usar varias veces en la misma sentencia, de forma que gracias a esta característica podremos concatenar el objeto endl al final, cuyo resultado será imprimir un retorno de línea. Por último tomaremos una secuencia de caracteres del teclado hasta el retorno de línea (presionando ENTER), llamando al método get del objeto cin.

4.1.2

Tipos de datos

C++ tiene los siguientes tipos fundamentales: • Caracteres: char (también es un entero), wchar_t • Enteros: short, int, long, long long • Números en coma flotante: float, double, long double • Booleanos: bool • Vacío: void El modificador unsigned se puede aplicar a enteros para obtener números sin signo (por omisión los enteros contienen signo), con lo que se consigue un rango mayor de números naturales. Tamaños asociados Según la máquina y el compilador que se utilice los tipos primitivos pueden ocupar un determinado tamaño en memoria. La siguiente lista ilustra el número de bits que ocupan los distintos tipos primitivos en la arquitectura x86. Otras arquitecturas pueden requerir distintos tamaños de tipos de datos primitivos. C++ no dice nada acerca de cuál es el número de bits en un byte, ni del tamaño de estos tipos; más bien, ofrece solamente las siguientes “garantías de tipos":


4.1. C++

39

• De acuerdo al estándar C99, un tipo char debe ocupar exactamente un byte compuesto de un mínimo de 8 bits independientemente de la arquitectura de la máquina. • El tamaño reconocido de char es de 1. Es decir, sizeof(char) siempre devuelve 1. • Un tipo short tiene al menos el mismo tamaño que un tipo char. • Un tipo long tiene al menos el doble tamaño en bytes que un tipo short. • Un tipo int tiene un tamaño entre el de short y el de long, ambos inclusive, preferentemente el tamaño de un apuntador de memoria de la máquina. Su valor máximo es 2147488281, usando 32 bits. • Un tipo unsigned tiene el mismo tamaño que su versión signed. Wchar_t Para la versión del estándar que se publicó en 1998, se decidió añadir el tipo de dato wchar_t, que permite el uso de caracteres UNICODE, a diferencia del tradicional char, que contempla simplemente al código de caracteres ASCII extendido. A su vez, se ha definido para la mayoría de las funciones y clases, tanto de C como de C++, una versión para trabajar con wchar_t, donde usualmente se prefija el carácter w al nombre de la función (en ocasiones el carácter es un infijo). Por ejemplo: • strcpy - wstrcpy • std::string - std::wstring • std::cout - std::wcout Cabe resaltar que en C se define wchar_t como: typedef unsigned short wchar_t; Mientras que en C++ es en sí mismo un tipo de dato. La palabra reservada “void” La palabra reservada void define en C++ el concepto de no existencia o no atribución de un tipo en una variable o declaración. Es decir, una función declarada como void no devolverá ningún valor. Esta palabra reservada también puede usarse para indicar que una función no recibe parámetros, como en la siguiente declaración: int funcion (void); Aunque la tendencia actual es la de no colocar la palabra “void”. Además se utiliza para determinar que una función no retorna un valor, como en: void funcion (int parametro); Cabe destacar que void no es un tipo. Una función como la declarada anteriormente no puede retornar un valor por medio de return: la palabra clave va sola. No es posible una declaración del tipo: void t; //Está mal En este sentido, void se comporta de forma ligeramente diferente a como lo hace en C, especialmente en cuanto a su significado en declaraciones y prototipos de funciones. Sin embargo, la forma especial void * indica que el tipo de datos es un puntero. Por ejemplo: void *memoria; Indica que memoria es un puntero a alguna parte, donde se guarda información de algún tipo. El programador es responsable de definir estos “algún”, eliminando toda ambigüedad. Una ventaja de la declaración "void *" es que


40

CAPÍTULO 4. TIPOS DE LENGUAJES

puede representar a la vez varios tipos de datos, dependiendo de la operación de cast escogida. La memoria que hemos apuntado en alguna parte, en el ejemplo anterior, bien podría almacenar un entero, un flotante, una cadena de texto o un programa, o combinaciones de éstos. Es responsabilidad del programador recordar qué tipo de datos hay y garantizar el acceso adecuado. La palabra “NULL” Además de los valores que pueden tomar los tipos anteriormente mencionados, existe un valor llamado NULL, sea el caso numérico para los enteros, caracter para el tipo char, cadena de texto para el tipo string, etc. El valor NULL, expresa, por lo regular, la representación de una Macro, asignada al valor “0”. Tenemos entonces que: void* puntero = NULL; int entero = NULL; bool boleana = NULL; char caracter = NULL; El valor de las variables anteriores nos daría 0. A diferencia de la variable “caracter”, que nos daría el equivalente a NULL, '\0', para caracteres.

4.1.3

Principios

Todo programa en C++ debe tener la función principal main() (a no ser que se especifique en tiempo de compilación otro punto de entrada, que en realidad es la función que tiene el main()) int main() {} La función principal del código fuente main debe tener uno de los siguientes prototipos: int main() int main(int argc, char** argv) Aunque no es estándar algunas implementaciones permiten int main(int argc, char** argv, char** env) La primera es la forma por omisión de un programa que no recibe parámetros ni argumentos. La segunda forma tiene dos parámetros: argc, un número que describe el número de argumentos del programa (incluyendo el nombre del programa mismo), y argv, un puntero a un array de punteros, de argc elementos, donde el elemento argv[i] representa el i-ésimo argumento entregado al programa. En el tercer caso se añade la posibilidad de poder acceder a las variables de entorno de ejecución de la misma forma que se accede a los argumentos del programa, pero reflejados sobre la variable env. El tipo de retorno de main es un valor entero int. Al finalizar la función main, debe incluirse el valor de retorno (por ejemplo, return 0;, aunque el estándar prevé solamente dos posibles valores de retorno: EXIT_SUCCESS y EXIT_FAILURE, definidas en el archivo cstdlib), o salir por medio de la función exit. Alternativamente puede dejarse en blanco, en cuyo caso el compilador es responsable de agregar la salida adecuada.

4.1.4

El concepto de clase

Los objetos en C++ son abstraídos mediante una clase. Según el paradigma de la programación orientada a objetos un objeto consta de: 1. Identidad, que lo diferencia de otros objetos (Nombre que llevará la clase a la que pertenece dicho objeto). 2. Métodos o funciones miembro 3. Atributos o variables miembro Un ejemplo de clase que podemos tomar es la clase perro. Cada perro comparte unas características (atributos). Su número de patas, el color de su pelaje o su tamaño son algunos de sus atributos. Las funciones que lo hagan ladrar, cambiar su comportamiento... esas son las funciones de la clase.


4.1. C++

41

Este es otro ejemplo de una clase: class Punto { //por defecto los miembros son 'private' para que sólo se puedan modificar desde la propia clase. private: // Variable miembro privada int id; protected: // Variables miembro protegidas int x; int y; public: // Constructor Punto(); // Destructor ~Punto(); // Funciones miembro o métodos int ObtenerX(); int ObtenerY(); };

Constructores Son unos métodos especiales que se ejecutan automáticamente al crear un objeto de la clase. En su declaración no se especifica el tipo de dato que devuelven, y poseen el mismo nombre que la clase a la que pertenecen. Al igual que otros métodos, puede haber varios constructores sobrecargados, aunque no pueden existir constructores virtuales. Como característica especial a la hora de implementar un constructor, justo después de la declaración de los parámetros, se encuentra lo que se llama “lista de inicializadores”. Su objetivo es llamar a los constructores de los atributos que conforman el objeto a construir. Cabe destacar que no es necesario declarar un constructor al igual que un destructor, pues el compilador lo puede hacer, aunque no es la mejor forma de programar. Tomando el ejemplo de la Clase Punto, si deseamos que cada vez que se cree un objeto de esta clase las coordenadas del punto sean igual a cero podemos agregar un constructor como se muestra a continuación: class Punto { public: float x; // Coordenadas del punto float y; // Constructor Punto() : x(0), y(0){ // Inicializamos las variables “x” e “y” } }; // Main para demostrar el funcionamiento de la clase # include <iostream> // Esto nos permite utilizar “cout” using namespace std; int main () { Punto MiPunto; // creamos un elemento de la clase Punto llamado MiPunto cout << “Coordenada X: " << MiPunto.x << endl; // mostramos el valor acumulado en la variable x cout << “Coordenada Y: " << MiPunto.y << endl; // mostramos el valor acumulado en la variable y getchar(); // le indicamos al programa que espere al buffer de entrada (detenerse) return 0; } Si compilamos y ejecutamos el anterior programa, obtenemos una salida que debe ser similar a la siguiente: Coordenada X: 0 Coordenada Y: 0 Existen varios tipos de constructores en C++: 1. Constructor predeterminado. Es el constructor que no recibe ningún parámetro en la función. Si no se definiera ningún constructor, el sistema proporcionaría uno predeterminado. Es necesario para la construcción de estructuras y contenedores de la STL. 2. Constructor de copia. Es un constructor que recibe un objeto de la misma clase, y realiza una copia de los atributos del mismo. Al igual que el predeterminado, si no se define, el sistema proporciona uno. 3. Constructor de conversión. Este constructor, recibe como único parámetro, un objeto o variable de otro tipo distinto al suyo propio. Es decir, convierte un objeto de un tipo determinado a otro objeto del tipo que estamos generando. Constructores + Memoria heap Un objeto creado de la forma que se vio hasta ahora, es un objeto que vive dentro del scope(las llaves { }) en el que fue creado. Para que un objeto pueda seguir viviendo cuando se saque de el scope en el que se creó, se lo debe crear en memoria heap. Para esto, se utiliza el operador new, el cual asigna memoria para almacenar al objeto creado, y además llama a su constructor(por lo que se le pueden enviar parámetros). El operador new se utiliza de la siguiente manera: int main() { Punto *unPunto = new Punto(); //esto llama al constructor que se describe más arriba delete unPunto; //no hay que olvidarse de liberar la memoria ocupada por el objeto(ver la sección destructores, más abajo) return 0; } Además, con el operador new[] se pueden crear arrays (colecciones o listas ordenadas) de tamaño dinámico: Punto *asignar(int cuantos) { return new Punto[cuantos]; //asigna un array de 'cuantos’ puntos(se llama el constructor que se muestra más arriba), y se retorna. }


42

CAPÍTULO 4. TIPOS DE LENGUAJES

Destructores Los destructores son funciones miembro especiales llamadas automáticamente en la ejecución del programa, y por tanto no tienen por qué ser llamadas explícitamente por el programador. Sus principales cometidos son: • Liberar los recursos computacionales que el objeto de dicha clase haya adquirido en tiempo de ejecución al expirar éste. • Quitar los vínculos que pudiesen tener otros recursos u objetos con éste. Los destructores son invocados automáticamente al alcanzar el flujo del programa el fin del ámbito en el que está declarado el objeto. El único caso en el que se debe invocar explícitamente al destructor de un objeto, es cuando éste fue creado mediante el operador new, es decir, que éste vive en memoria heap, y no en la pila de ejecución del programa. La invocación del destructor de un objeto que vive en heap se realiza a través del operador delete o delete[] para arrays. Ejemplo: int main() { int *unEntero = new int(12); //asignamos un entero en memoria heap con el valor 12 int *arrayDeEnteros = new int[25]; //asignamos memoria para 25 enteros(no estan inicializados) delete unEntero; //liberamos la memoria que ocupaba unEntero delete[] arrayDeEnteros; //liberamos la memoria ocupada por arrayDeEnteros return 0; } Si no se utilizara el operador delete y delete[] en ese caso, la memoria ocupada por unEntero y arrayDeEnteros respectivamente, quedaría ocupada sin sentido. Cuando una porción de memoria queda ocupada por una variable que ya no se utiliza, y no hay forma de acceder a ella, se denomina un 'memory leak'. En aplicaciones grandes, si ocurren muchos memory leaks, el programa puede terminar ocupando bastante más memoria RAM de la que debería, lo que no es para nada conveniente. Es por esto, que el manejo de memoria heap debe usarse conscientemente. Existen dos tipos de destructores pueden ser públicos o privados, según si se declaran: • Si es público se llama desde cualquier parte del programa para destruir el objeto. • Si es privado no se permite la destrucción del objeto por el usuario. El uso de destructores es clave en el concepto de Adquirir Recursos es Inicializar. Funciones miembro Función miembro es aquella que está declarada en ámbito de clase. Son similares a las funciones habituales, con la salvedad de que el compilador realizara el proceso de Decoración de nombre (Name Mangling en inglés): Cambiará el nombre de la función añadiendo un identificador de la clase en la que está declarada, pudiendo incluir caracteres especiales o identificadores numéricos. Este proceso es invisible al programador. Además, las funciones miembro reciben implícitamente un parámetro adicional: El puntero this, que referencia al objeto que ejecuta la función. Las funciones miembro se invocan accediendo primero al objeto al cual refieren, con la sintaxis: myobject.mymemberfunction(), esto es un claro ejemplo de una función miembro. Caso especial es el de las funciones miembro estáticas. A pesar de que son declaradas dentro de la clase, con el uso de la palabra clave static no recibirán el puntero this. Gracias a esto no es necesario crear ninguna instancia de la clase para llamar a esta función, sin embargo, sólo se podrá acceder a los miembros estáticos de la clase dado que estos no están asociados al objeto sino al tipo. La sintaxis para llamar a esta función estática es mytype::mystaticmember(). Plantillas Las plantillas son el mecanismo de C++ para implantar el paradigma de la programación genérica. Permiten que una clase o función trabaje con tipos de datos abstractos, especificándose más adelante cuales son los que se quieren usar. Por ejemplo, es posible construir un vector genérico que pueda contener cualquier tipo de estructura de datos. De esta forma se pueden declarar objetos de la clase de este vector que contengan enteros, flotantes, polígonos, figuras, fichas de personal, etc. La declaración de una plantilla se realiza anteponiendo la declaración template <typename A,....> a la declaración de la estructura (clase, estructura o función) deseado.


4.1. C++

43

Por ejemplo: template <typename T> T max(const T &x, const T &y) { return (x > y) ? x : y; //si x > y, retorna x, sino retorna y } La función max() es un ejemplo de programación genérica, y dados dos parámetros de un tipo T (que puede ser int, long, float, double, etc.) devolverá el mayor de ellos (usando el operador >). Al ejecutar la función con parámetros de un cierto tipo, el compilador intentará “calzar” la plantilla a ese tipo de datos, o bien generará un mensaje de error si fracasa en ese proceso.

Especialización

Clases abstractas En C++ es posible definir clases abstractas. Una clase abstracta, o clase base abstracta (ABC), es una que está diseñada sólo como clase padre de las cuales se deben derivar clases hijas. Una clase abstracta se usa para representar aquellas entidades o métodos que después se implementarán en las clases derivadas, pero la clase abstracta en sí no contiene ninguna implementación -- solamente representa los métodos que se deben implementar. Por ello, no es posible instanciar una clase abstracta, pero sí una clase concreta que implemente los métodos definidos en ella. Las clases abstractas son útiles para definir interfaces, es decir, un conjunto de métodos que definen el comportamiento de un módulo determinado. Estas definiciones pueden utilizarse sin tener en cuenta la implementación que se hará de ellos. En C++ los métodos de las clases abstractas se definen como funciones virtuales puras. class Abstracta { public: virtual int metodo() = 0; } class ConcretaA : public Abstracta { public: int metodo() { //haz algo return foo () + 2; } }; class ConcretaB : public Abstracta { public: int metodo() { //otra implementación return baz () - 5; } }; En el ejemplo, la clase ConcretaA es una implementación de la clase Abstracta, y la clase ConcretaB es otra implementación. Debe notarse que el = 0 es la notación que emplea C++ para definir funciones virtuales puras.

Espacios de nombres Una adición a las características de C son los espacios de nombre (namespace en inglés), los cuales pueden describirse como áreas virtuales bajo las cuales ciertos nombres de variable o tipos tienen validez. Esto permite evitar las ocurrencias de conflictos entre nombres de funciones, variables o clases. El ejemplo más conocido en C++ es el espacio de nombres std::, el cual almacena todas las definiciones nuevas en C++ que difieren de C (algunas estructuras y funciones), así como las funcionalidades propias de C++ (streams) y los componentes de la biblioteca STL. Por ejemplo: # include <iostream> // Las funciones en esta cabecera existen dentro del espacio de nombres std:: namespace mi_paquete{ int mi_valor; }; int main() { int mi_valor = 3; mi_paquete::mi_valor = 4; std::cout << mi_valor << '\n'; // imprime '3' std::cout << mi_paquete::mi_valor << '\n'; // imprime '4' return 0; } Como puede verse, las invocaciones directas a mi_valor darán acceso solamente a la variable descrita localmente; para acceder a la variable del espacio de nombres mi_paquete es necesario acceder específicamente el espacio de nombres. Un atajo recomendado para programas sencillos es la directiva using namespace, que permite acceder a los nombres de variables del paquete deseado en forma directa, siempre y cuando no se produzca alguna ambigüedad o conflicto de nombres.

Herencia Existen varios tipos de herencia entre clases en el lenguaje de programación C++. Estos son:


44

CAPÍTULO 4. TIPOS DE LENGUAJES

Herencia simple La herencia en C++ es un mecanismo de abstracción creado para poder facilitar y mejorar el diseño de las clases de un programa. Con ella se pueden crear nuevas clases a partir de clases ya hechas, siempre y cuando tengan un tipo de relación especial. En la herencia, las clases derivadas “heredan” los datos y las funciones miembro de las clases base, pudiendo las clases derivadas redefinir estos comportamientos (polimorfismo) y añadir comportamientos nuevos propios de las clases derivadas. Para no romper el principio de encapsulamiento (ocultar datos cuyo conocimiento no es necesario para el uso de las clases), se proporciona un nuevo modo de visibilidad de los datos/funciones: “protected”. Cualquier cosa que tenga visibilidad protected se comportará como pública en la clase Base y en las que componen la jerarquía de herencia, y como privada en las clases que NO sean de la jerarquía de la herencia. Antes de utilizar la herencia, nos tenemos que hacer una pregunta, y si tiene sentido, podemos intentar usar esta jerarquía: Si la frase <claseB> ES-UN <claseA> tiene sentido, entonces estamos ante un posible caso de herencia donde clase A será la clase base y clase B la derivada. Ejemplo: clases Barco, Acorazado, Carguero, etc. Un Acorazado ES-UN Barco, un Carguero ES-UN Barco, un Trasatlántico ES-UN Barco, etc. En este ejemplo tendríamos las cosas generales de un Barco (en C++) class Barco { protected: char* nombre; float peso; public: //Constructores y demás funciones básicas de barco }; y ahora las características de las clases derivadas, podrían (a la vez que heredan las de barco) añadir cosas propias del subtipo de barco que vamos a crear, por ejemplo: class Carguero: public Barco { // Esta es la manera de especificar que hereda de Barco private: float carga; //El resto de cosas }; class Acorazado: public Barco { private: int numeroArmas; int Soldados; // El resto de cosas }; Por último, hay que mencionar que existen 3 clases de herencia que se diferencian en el modo de manejar la visibilidad de los componentes de la clase resultante: • Herencia pública (class Derivada: public Base ): Con este tipo de herencia se respetan los comportamientos originales de las visibilidades de la clase Base en la clase Derivada. • Herencia privada (clase Derivada: private Base): Con este tipo de herencia todo componente de la clase Base, será privado en la clase Derivada (las propiedades heredadas serán privadas aunque estas sean públicas en la clase Base) • Herencia protegida (clase Derivada: protected Base): Con este tipo de herencia, todo componente público y protegido de la clase Base, será protegido en la clase Derivada, y los componentes privados, siguen siendo privados. Herencia múltiple La herencia múltiple es el mecanismo que permite al programador hacer clases derivadas a partir, no de una sola clase base, sino de varias. Para entender esto mejor, pongamos un ejemplo: Cuando ves a quien te atiende en una tienda, como persona que es, podrás suponer que puede hablar, comer, andar, pero, por otro lado, como empleado que es, también podrás suponer que tiene un jefe, que puede cobrarte dinero por la compra, que puede devolverte el cambio, etc. Si esto lo trasladamos a la programación sería herencia múltiple (clase empleado_tienda): class Persona { ... Hablar(); Caminar(); ... }; class Empleado { Persona jefe; int sueldo; Cobrar(); ... }; class EmpleadoTienda: public Persona, Empleado { ... AlmacenarStock(); ComprobarExistencias(); ... }; Por tanto, es posible utilizar más de una clase para que otra herede sus características. Sobrecarga de operadores La sobrecarga de operadores es una forma de hacer polimorfismo. Es posible definir el comportamiento de un operador del lenguaje para que trabaje con tipos de datos definidos por el usuario. No todos los operadores de C++ son factibles de sobrecargar, y, entre aquellos que pueden ser sobrecargados, se deben cumplir condiciones especiales. En particular, los operadores sizeof y :: no son sobrecargables. No es posible en C++ crear un operador nuevo.


4.1. C++

45

Los comportamientos de los operadores sobrecargados se implementan de la misma manera que una función, salvo que esta tendrá un nombre especial: Tipo de dato de devolución operator<token del operador>(parámetros) Los siguientes operadores pueden ser sobrecargados: • Operadores Unarios • • • • • • •

Operador * (de indirección) Operador -> (de indirección) Operador & (de dirección) Operador + Operador Operador ++ Operador --

• Operadores Binarios • • • • • • • • • • • • •

Operador == Operador + Operador Operador * Operador / Operador % Operador << Operador >> Operador & Operador ^ Operador | Operador [] Operador ()

• Operadores de Asignación • • • • • • • • • • •

Operador = Operador += Operador -= Operador *= Operador /= Operador %= Operador <<= Operador >>= Operador &= Operador ^= Operador |=

Dado que estos operadores son definidos para un tipo de datos definido por el usuario, éste es libre de asignarles cualquiera semántica que desee. Sin embargo, se considera de primera importancia que las semánticas sean tan parecidas al comportamiento natural de los operadores como para que el uso de los operadores sobrecargados sea intuitivo. Por ejemplo, el uso del operador unario - debiera cambiar el “signo” de un “valor”. Los operadores sobrecargados no dejan de ser funciones, por lo que pueden devolver un valor, si este valor es del tipo de datos con el que trabaja el operador, permite el encadenamiento de sentencias. Por ejemplo, si tenemos 3 variables A, B y C de un tipo T y sobrecargamos el operador = para que trabaje con el tipo de datos T, hay dos opciones: si el operador no devuelve nada una sentencia como “A=B=C;" (sin las comillas) daría error, pero si se devuelve un tipo de datos T al implementar el operador, permitiría concatenar cuantos elementos se quisieran, permitiendo algo como “A=B=C=D=...;"


46

4.1.5

CAPÍTULO 4. TIPOS DE LENGUAJES

Standard Template Library (STL)

Los lenguajes de programación suelen tener una serie de bibliotecas de funciones integradas para la manipulación de datos a nivel más básico. En C++, además de poder usar las bibliotecas de C, se puede usar la nativa STL (Standard Template Library), propia del lenguaje. Proporciona una serie plantillas (templates) que permiten efectuar operaciones sobre el almacenado de datos, procesado de entrada/salida.

4.1.6

Biblioteca de entrada y salida

Las clases basic_ostream y basic_stream, y los objetos cout y cin, proporcionan la entrada y salida estándar de datos (teclado/pantalla). También está disponible cerr, similar a cout, usado para la salida estándar de errores. Estas clases tienen sobrecargados los operadores << y >>, respectivamente, con el objeto de ser útiles en la inserción/extracción de datos a dichos flujos. Son operadores inteligentes, ya que son capaces de adaptarse al tipo de datos que reciben, aunque tendremos que definir el comportamiento de dicha entrada/salida para clases/tipos de datos definidos por el usuario. Por ejemplo: ostream& operator<<(ostream& fs, const Punto& punto) { return fs << punto.x << ",” << punto.y; } De esta forma, para mostrar un punto, solo habría que realizar la siguiente expresión: //... Punto p(4,5); //... cout << “Las coordenadas son: " << p << endl; //... Es posible formatear la entrada/salida, indicando el número de dígitos decimales a mostrar, si los textos se pasarán a minúsculas o mayúsculas, si los números recibidos están en formato octal o hexadecimal, etc. Fstreams Tipo de flujo para el manejo de ficheros. La definición previa de ostreams/istreams es aplicable a este apartado. Existen tres clases (ficheros de lectura, de escritura o de lectura/escritura): ifstream,ofstream y fstream. Como abrir un fichero: (nombre_variable_fichero).open(“nombre_fichero.dat/txt”, ios::in); para abrirlo en modo lectura. (nombrevariablefichero).open(“nombre_fichero.dat/txt”, ios::out); para abrirlo en modo escritura. Ejemplo: f.open(“datos.txt”, ios::in); Como cerrar el fichero: nombre_variable_fichero.close(); Ejemplo: f.close(); Leer un fichero: 1-Si es fichero de texto plano: #include <fstream> #include <string> #include <iostream> using namespace std; int main() { ifstream entrada; entrada.open(“textoPlano.txt”); string unString; while(entrada >> unString) cout << “Lei: " << unString << endl; return 0; } 2-Si es un fichero binario(.dat); nombre_variable_fichero.read((char*)&nombre_variable, sizeof(tipo_variable)); Ejemplo: f.read((char*)&e, sizeof(int)); Escribir un fichero:

1-Si es fichero de texto(.txt): nombrevariable<<"texto"; donde “texto” puede ser también una variable de cualquier tipo primitivo, o un string. Ejemplo: f<<HOLA; 2-Si es un fichero binario(.dat); nombre_variable_fichero.write((char*)&nombre_variable sizeof(tipo_variable)); Ejemplo: f.write((char*)&e, sizeof(int)); Pueden abrirse pasando al constructor los parámetros relativos a la ubicación del fichero y el modo de apertura: Sstreams Se destacan dos clases, ostringstream e istringstream. Todo lo anteriormente dicho es aplicable a estas clases. Tratan a una cadena como si de un flujo de datos se tratase. ostringstream permite elaborar una cadena de texto insertando datos cual flujo, e istringstream puede extraer la información contenida en una cadena (pasada como parámetro en su constructor) con el operador >>. Ejemplos:


4.1. C++

47

ostringstream s; s << nombre << ",” << edad << ",” << estatura << ",” << punto(5,6) << endl; cout << s.str(); istringstream s(cadena); s >> nombre >> edad >> estatura >> p;

Contenedores Son clases plantillas especiales utilizadas para almacenar tipos de datos genéricos, sean cuales sean. Todos los contenedores son homogéneos, es decir, una vez que se declaran para contener un tipo de dato determinado, en ese contenedor, solo se podrán meter elementos de ese tipo. Según la naturaleza del almacenado, disponemos de varios tipos: • Vectores: Se definen por vector<tipo_de_dato> nombre_del_vector; Son arrays (o listas ordenadas) que se redimensionan automáticamente al agregar nuevos elementos, por lo que se le pueden agregar “teóricamente”, infinitos elementos. Los vectores nos permiten acceder a cualquier elemento que contenga, mediante el operador[]. Debe tenerse en cuenta que si se intenta acceder a una posición que excede los límites del vector, este no hará ningún chequeo, por lo que se debe ser cuidadoso al utilizar este operador. Para asegurar un acceso seguro al vector, se puede utilizar el método at(int), que lanza una excepción de tipo std::out_of_range en caso de que esto ocurra. Para añadir elementos al final del vector, se utiliza el método push_back(const T&). Por otro lado, para eliminar un elemento del final del vector, se debe usar el método pop_back(). #include <vector> //libreria que contiene a la clase vector #include <iostream> using namespace std; int main() { vector<int> intVector; //crea un vector de enteros(sin elementos) intVector.push_back(25); //agrega el entero 25 al vector cout << “El primer elemento es: " << intVector.front() << " y mi vector tiene " << intVector.size() << " elementos.” << endl; //imprime el primer elemento(retornado por el método front() intVector.push_back(32); //agrego el entero 32 al vector cout << “El primer elemento es: " << intVector[0] << endl; //imprime 25 intVector.pop_back(); //elimina el ultimo elemento del vector(osea 32) cout << “Ahora tengo: " << intVector.size() << " elementos.” << endl; //imprimirá 1 return 0; }

• Colas dobles: son parecidas a los vectores, pero tienen mejor eficiencia para agregar o eliminar elementos en las “puntas”.deque<tipo_de_dato> nombre_de_la_cola; Además de los métodos push_back(const T&) y pop_back(), se agregan los métodos push_front(const T&) y pop_front(), que realizan lo mismo que los ya explicados, pero en el comienzo de la cola. #include <deque> //libreria de deques using namespace std; int main() { deque<int> intDeque; intDeque.push_front(25); intDeque.push_back(12); while(intDeque.size()) intDeque.pop_back(); //borra todos los elementos return 0; }

• Listas: Son eficientes a la hora de agregar elementos. La diferencia con las colas dobles, es que son más eficientes para eliminar elementos que no estén en alguna de las “puntas"list<tipo_de_dato> nombre_de_la_lista; • Adaptadores de secuencia. • Contenedores asociativos: map y multimap, que permiten asociar una “clave” con un “valor”. map no permite valores repetidos, mientras que multimap si. map<tipo_de_llave, tipo_de_dato> nombre_del_map; multimap<tipo_de_llave, tipo_de_dato> nombre_del_multimap; #include <map> //libreria que contiene a map y multimap #include <string> //libreria de strings #include <iostream> //libreria de entrada/salida using namespace std; int main() { map<int, string> intAString; intAString[1] = “uno"; intAString[10] = “diez"; cout << “En intAString[1]: " << intAString[1] << endl; cout << “En intAString[10]: " << intAString[10] << endl; return 0; }

• Contenedores asociativos: set y multiset, que ofrecen solamente la condición de “pertenencia”, sin la necesidad de garantizar un ordenamiento particular de los elementos que contienen.


48

CAPÍTULO 4. TIPOS DE LENGUAJES

Iteradores Pueden considerarse como una generalización de la clase de “puntero”. Un iterador es un tipo de dato que permite el recorrido y la búsqueda de elementos en los contenedores. Como las estructuras de datos (contenedores) son clases genéricas, y los operadores (algoritmos) que deben operar sobre ellas son también genéricos (funciones genéricas), Stepanov y sus colaboradores tuvieron que desarrollar el concepto de iterador como elemento o nexo de conexión entre ambos. El nuevo concepto resulta ser una especie de punteros que señalan a los diversos miembros del contenedor (punteros genéricos que como tales no existen en el lenguaje).

Algoritmos Combinando la utilización de templates y un estilo específico para denotar tipos y variables, la STL ofrece una serie de funciones que representan operaciones comunes, y cuyo objetivo es “parametrizar” las operaciones en que estas funciones se ven involucradas de modo que su lectura, comprensión y mantenimiento, sean más fáciles de realizar. Un ejemplo es la función copy, la cual simplemente copia variables desde un lugar a otro. Más estrictamente, copia los contenidos cuyas ubicaciones están delimitadas por dos iteradores, al espacio indicado por un tercer iterador. La sintaxis es: copy (inicio_origen, fin_origen, inicio_destino); De este modo, todos los datos que están entre inicio_origen y fin_origen, excluyendo el dato ubicado en este último, son copiados a un lugar descrito o apuntado por inicio_destino. Un algoritmo muy importante que viene implementado en la biblioteca STL, es el sort. El algoritmo sort, ordena cualquier tipo de contenedor, siempre y cuando se le pasen como argumentos, desde donde y hasta donde se quiere ordenarlo. #include <vector> #include <deque> #include <algorithm> int main() { vector<int> intVector; intVector.push_back(60); intVector.push_back(12); intVector.push_back(54); //para este momento, el vector tiene 60,12,54 sort(intVector.begin(), intVector.end()); //listo, array ordenado, ahora tiene 12,54,60 /*Notar que si en vez de un vector, fuese una deque, se ordenaría de la misma manera. */ } Entre las funciones más conocidas están swap (variable1, variable2), que simplemente intercambia los valores de variable1 y variable2; max (variable1, variable2) y su símil min (variable1, variable2), que retornan el máximo o mínimo entre dos valores; find (inicio, fin, valor) que busca valor en el espacio de variables entre inicio y fin; etcétera. Los algoritmos son muy variados, algunos incluso tienen versiones específicas para operar con ciertos iteradores o contenedores, y proveen un nivel de abstracción extra que permite obtener un código más “limpio”, que “describe” lo que se está haciendo, en vez de hacerlo paso a paso explícitamente.

4.1.7

C++11

El 12 de agosto de 2011, Herb Sutter, presidente del comité de estándares de C++, informó la aprobación unánime del nuevo estándar.[2] La publicación del mismo se espera para algún momento de 2011. Entre las características del nuevo estándar se pueden destacar: • Funciones lambda; • Referencias rvalue; • La palabra reservada auto; • Inicialización uniforme; • Plantillas con número variable de argumentos. Además se ha actualizado la biblioteca estándar del lenguaje.


4.1. C++

4.1.8

49

Actualidad y futuro

La continuidad del C++11 es C++14, que es la versión actual, y en el futuro, se estima que a finales de 2017, será C++17

4.1.9

Diferencias de tipos respecto a C

En C++, cualquier tipo de datos que sea declarado completo (fully qualified, en inglés) se convierte en un tipo de datos único. Las condiciones para que un tipo de datos T sea declarado completo son a grandes rasgos las siguientes: • Es posible al momento de compilación conocer el espacio asociado al tipo de datos (es decir, el compilador debe conocer el resultado de sizeof(T)). • T Tiene al menos un constructor, y un destructor, bien declarados. • Si T es un tipo compuesto, o es una clase derivada, o es la especificación de una plantilla, o cualquier combinación de las anteriores, entonces las dos condiciones establecidas previamente deben aplicar para cada tipo de dato constituyente. En general, esto significa que cualquier tipo de datos definido haciendo uso de las cabeceras completas, es un tipo de datos completo. En particular, y, a diferencia de lo que ocurría en C, los tipos definidos por medio de struct o enum son tipos completos. Como tales, ahora son sujetos a sobrecarga, conversiones implícitas, etcétera. Los tipos enumerados, entonces, ya no son simplemente alias para tipos enteros, sino que son tipos de datos únicos en C++. El tipo de datos bool, igualmente, pasa a ser un tipo de datos único, mientras que en C funcionaba en algunos casos como un alias para alguna clase de dato de tipo entero.

4.1.10

Compiladores

Uno de los compiladores libres de C++ es el de GNU, el compilador G++ (parte del proyecto GCC, que engloba varios compiladores para distintos lenguajes). Otros compiladores comunes son Intel C++ Compiler, el compilador de Xcode, el compilador de Borland C++, el compilador de CodeWarrior C++, el compilador g++ de Cygwin, el compilador g++ de MinGW, el compilador de Visual C++, Carbide.c++, entre otros.

4.1.11

Ejemplo: Cmd con colores

Para cambiar el color de la interfaz del programa se necesita la librería “stdlib.h”. su aplicación sirve para cambiar el color de fondo del cmd y el color de las letras. Nota: Esto únicamente funciona en sistemas Windows, Uso

#include <stdlib.h> using namespace std; system(“color 45”);

En este caso se ha definido el fondo de pantalla de color rojo y las letras rosadas.

4.1.12

Entornos de desarrollo

Bajo Microsoft Windows • Visual Studio Code • Code::Blocks • Dev-C++ • Visual C++


50

CAPÍTULO 4. TIPOS DE LENGUAJES • wxDev-C++ • Zinjai • Open Watcom (IDE y Dialog Editor) • CodeLite

Bajo MacOS • Xcode • Zinjai • CodeLite Bajo DOS • Turbo C, reemplazado por C++Builder Bajo GNU/Linux • Code::Blocks • NetBeans • Eclipse • Geany • Emacs • Zinjai • Kdevelop • Open Watcom (IDE y Dialog Editor) • CodeLite

4.1.13

Véase también

• A++ • C++/CX

4.1.14

Referencias

[1] Stroustrup, Bjarne (1997). «1». The C++ Programming Language (Third edición). ISBN 0201889544. OCLC 59193992. [2] http://herbsutter.com/2011/08/12/we-have-an-international-standard-c0x-is-unanimously-approved/

Bibliografía • Bjarne Stroustrup, El lenguaje de programación C++, Addison Wesley, Madrid, 1998, ISBN 84-7829-019-2 • Bjarne Stroustrup, The C++ Programming Language, Addison-Wesley Pub Co; Tercera edición (15 de febrero de 2000); ISBN 0-201-70073-5 • Bjarne Stroustrup, The Design and Evolution of C++, Addison-Wesley Pub Cp; Primera edición (29 de marzo de 1994); ISBN 0-201-54330-3 • Margaret A. Ellis y Bjarne Stroustrup, The Annotated C++ Reference Manual, Addison-Wesley Pub Co; (1 de enero de 1990); ISBN 0-201-51459-1


4.2. JAVA (LENGUAJE DE PROGRAMACIÓN)

4.1.15 •

51

Enlaces externos Wikimedia Commons alberga contenido multimedia sobre C++. Commons

• «Cplusplus resources» (en inglés). Consultado el 10 de abril de 2015. • «C/C++ Reference=C Programming and C++ Programming» (en inglés). Consultado el 10 de abril de 2015.

4.2 Java (lenguaje de programación) Java es un lenguaje de programación de propósito general, concurrente, orientado a objetos que fue diseñado específicamente para tener tan pocas dependencias de implementación como fuera posible. Su intención es permitir que los desarrolladores de aplicaciones escriban el programa una vez y lo ejecuten en cualquier dispositivo (conocido en inglés como WORA, o "write once, run anywhere"), lo que quiere decir que el código que es ejecutado en una plataforma no tiene que ser recompilado para correr en otra. Java es, a partir de 2012, uno de los lenguajes de programación más populares en uso, particularmente para aplicaciones de cliente-servidor de web, con unos 10 millones de usuarios reportados.[1][2] El lenguaje de programación Java fue originalmente desarrollado por James Gosling de Sun Microsystems (la cual fue adquirida por la compañía Oracle) y publicado en 1995 como un componente fundamental de la plataforma Java de Sun Microsystems. Su sintaxis deriva en gran medida de C y C++, pero tiene menos utilidades de bajo nivel que cualquiera de ellos. Las aplicaciones de Java son generalmente compiladas a bytecode (clase Java) que puede ejecutarse en cualquier máquina virtual Java (JVM) sin importar la arquitectura de la computadora subyacente. La compañía Sun desarrolló la implementación de referencia original para los compiladores de Java, máquinas virtuales, y librerías de clases en 1991 y las publicó por primera vez en 1995. A partir de mayo de 2007, en cumplimiento con las especificaciones ɖel Proceso de la Comunidad Java, Sun volvió a licenciar la mayoría de sus tecnologías de Java bajo la Licencia Pública General de GNU. Otros también han desarrollado implementaciones alternas a estas tecnologías de Sun, tales como el Compilador de Java de GNU y el GNU Classpath.

4.2.1

Historia

Java se creó como una herramienta de programación para ser usada en un proyecto de set-top-box en una pequeña operación denominada the Green Project en Sun Microsystems en el año 1991. El equipo (Green Team), compuesto por trece personas y dirigido por James Gosling, trabajó durante 18 meses en Sand Hill Road en Menlo Park en su desarrollo. El lenguaje se denominó inicialmente Oak (por un roble que había fuera de la oficina de Gosling), luego pasó a denominarse Green tras descubrir que Oak era ya una marca comercial registrada para adaptadores de tarjetas gráficas y finalmente se renombró a Java. Es frecuentada por algunos de los miembros del equipo. Pero no está claro si es un acrónimo o no, aunque algunas fuentes señalan que podría tratarse de las iniciales de sus diseñadores: James Gosling, Arthur Van Hoff, y Andy Bechtolsheim. Otros abogan por el siguiente acrónimo, Just Another Vague Acronym (“sólo otro acrónimo ambiguo más”). La hipótesis que más fuerza tiene es la de que Java debe su nombre a un tipo de café disponible en la cafetería cercana, de ahí que el icono de java sea una taza de café caliente. Un pequeño signo que da fuerza a esta teoría es que los 4 primeros bytes (el número mágico) de los archivos.class que genera el compilador, son en hexadecimal, 0xCAFEBABE. A pesar de todas estas teorías, el nombre fue sacado al parecer de una lista aleatoria de palabras.[3] Los objetivos de Gosling eran implementar una máquina virtual y un lenguaje con una estructura y sintaxis similar a C++. Entre junio y julio de 1994, tras una sesión maratoniana de tres días entre John Gaga, James Gosling, Patrick Naughton, Wayne Rosing y Eric Schmidt, el equipo reorientó la plataforma hacia la Web. Sintieron que la llegada del navegador web Mosaic, propiciaría que Internet se convirtiese en un medio interactivo, como el que pensaban era la televisión por cable. Naughton creó entonces un prototipo de navegador, WebRunner, que más tarde sería conocido como HotJava. En 1994, se les hizo una demostración de HotJava y la plataforma Java a los ejecutivos de Sun. Java 1.0a pudo descargarse por primera vez en 1994, pero hubo que esperar al 23 de mayo de 1995, durante las conferencias de SunWorld, a que vieran la luz pública Java y HotJava, el navegador Web. El acontecimiento fue anunciado por John


52

CAPÍTULO 4. TIPOS DE LENGUAJES

Gage, el Director Científico de Sun Microsystems. El acto estuvo acompañado por una pequeña sorpresa adicional, el anuncio por parte de Marc Andreessen, Vicepresidente Ejecutivo de Netscape, de que Java sería soportado en sus navegadores. El 9 de enero del año siguiente, 1996, Sun fundó el grupo empresarial JavaSoft para que se encargase del desarrollo tecnológico. Dos semanas más tarde la primera versión de Java fue publicada. La promesa inicial de Gosling era Write Once, Run Anywhere (Escríbelo una vez, ejecútalo en cualquier lugar), proporcionando un lenguaje independiente de la plataforma y un entorno de ejecución (la JVM) ligero y gratuito para las plataformas más populares de forma que los binarios (bytecode) de las aplicaciones Java pudiesen ejecutarse en cualquier plataforma. El entorno de ejecución era relativamente seguro y los principales navegadores web pronto incorporaron la posibilidad de ejecutar applets Java incrustadas en las páginas web. Java ha experimentado numerosos cambios desde la versión primigenia, JDK 1.0, así como un enorme incremento en el número de clases y paquetes que componen la biblioteca estándar.[4] Desde J2SE 1.4, la evolución del lenguaje ha sido regulada por el JCP (Java Community Process), que usa Java Specification Requests (JSRs) para proponer y especificar cambios en la plataforma Java. El lenguaje en sí mismo está especificado en la Java Language Specification (JLS), o Especificación del Lenguaje Java. Los cambios en los JLS son gestionados en JSR 901. • JDK 1.0 (23 de enero de 1996) — Primer lanzamiento: comunicado de prensa • JDK 1.1 (19 de febrero de 1997) — Principales adiciones incluidas: comunicado de prensa • una reestructuración intensiva del modelo de eventos AWT (Abstract Windowing Toolkit) • clases internas (inner classes) • JavaBeans • JDBC (Java Database Connectivity), para la integración de bases de datos • RMI (Remote Method Invocation) • J2SE 1.2 (8 de diciembre de 1998) — Nombre clave Playground. Esta y las siguientes versiones fueron recogidas bajo la denominación Java 2 y el nombre “J2SE” (Java 2 Platform, Standard Edition), reemplazó a JDK para distinguir la plataforma base de J2EE (Java 2 Platform, Enterprise Edition) y J2ME (Java 2 Platform, Micro Edition). Otras mejoras añadidas incluían: comunicado de prensa • la palabra reservada (keyword) strictfp • reflexión en la programación • la API gráfica ( Swing) fue integrada en las clases básicas • la máquina virtual (JVM) de Sun fue equipada con un compilador JIT (Just in Time) por primera vez • Java Plug-in • Java IDL, una implementación de IDL (Lenguaje de Descripción de Interfaz) para la interoperabilidad con CORBA • Colecciones (Collections) • J2SE 1.3 (8 de mayo de 2000) — Nombre clave Kestrel. Los cambios más notables fueron:comunicado de prensa lista completa de cambios • la inclusión de la máquina virtual de HotSpot JVM (la JVM de HotSpot fue lanzada inicialmente en abril de 1999, para la JVM de J2SE 1.2) • RMI fue cambiado para que se basara en CORBA • JavaSound • se incluyó el Java Naming and Directory Interface (JNDI) en el paquete de bibliotecas principales (anteriormente disponible como una extensión) • Java Platform Debugger Architecture (JPDA)


4.2. JAVA (LENGUAJE DE PROGRAMACIÓN)

53

• J2SE 1.4 (6 de febrero de 2002) — Nombre Clave Merlin. Este fue el primer lanzamiento de la plataforma Java desarrollado bajo el Proceso de la Comunidad Java como JSR 59. Los cambios más notables fueron: comunicado de prensalista completa de cambios • Palabra reservada assert (Especificado en JSR 41.) • Expresiones regulares modeladas al estilo de las expresiones regulares Perl • Encadenación de excepciones Permite a una excepción encapsular la excepción de bajo nivel original. • non-blocking NIO (New Input/Output) (Especificado en JSR 51.) • Logging API (Specified in JSR 47.) • API I/O para la lectura y escritura de imágenes en formatos como JPEG o PNG • Parser XML integrado y procesador XSLT (JAXP) (Especificado en JSR 5 y JSR 63.) • Seguridad integrada y extensiones criptográficas (JCE, JSSE, JAAS) • Java Web Start incluido (El primer lanzamiento ocurrió en marzo de 2001 para J2SE 1.3) (Especificado en JSR 56.) • J2SE 5.0 (30 de septiembre de 2004) — Nombre clave: Tiger. (Originalmente numerado 1.5, esta notación aún es usada internamente.) Desarrollado bajo JSR 176, Tiger añadió un número significativo de nuevas características comunicado de prensa • Plantillas (genéricos) — provee conversión de tipos (type safety) en tiempo de compilación para colecciones y elimina la necesidad de la mayoría de conversión de tipos (type casting). (Especificado por JSR 14.) • Metadatos — también llamados anotaciones, permite a estructuras del lenguaje como las clases o los métodos, ser etiquetados con datos adicionales, que puedan ser procesados posteriormente por utilidades de proceso de metadatos. (Especificado por JSR 175.) • Autoboxing/unboxing — Conversiones automáticas entre tipos primitivos (Como los int) y clases de envoltura primitivas (Como Integer). (Especificado por JSR 201.) • Enumeraciones — la palabra reservada enum crea una typesafe, lista ordenada de valores (como Dia.LUNES, Dia.MARTES, etc.). Anteriormente, esto solo podía ser llevado a cabo por constantes enteras o clases construidas manualmente (enum pattern). (Especificado por JSR 201.) • Varargs (número de argumentos variable) — El último parámetro de un método puede ser declarado con el nombre del tipo seguido por tres puntos (e.g. void drawtext(String... lines)). En la llamada al método, puede usarse cualquier número de parámetros de ese tipo, que serán almacenados en un array para pasarlos al método. • Bucle for mejorado — La sintaxis para el bucle for se ha extendido con una sintaxis especial para iterar sobre cada miembro de un array o sobre cualquier clase que implemente Iterable, como la clase estándar Collection, de la siguiente forma: void displayWidgets (Iterable<Widget> widgets) { for (Widget w : widgets) { w.display(); } } Este ejemplo itera sobre el objeto Iterable widgets, asignando, en orden, cada uno de los elementos a la variable w, y llamando al método display() de cada uno de ellos. (Especificado por JSR 201.) • Java SE 6 (11 de diciembre de 2006) — Nombre clave Mustang. Estuvo en desarrollo bajo la JSR 270. En esta versión, Sun cambió el nombre “J2SE” por Java SE y eliminó el ".0” del número de versión.. Está disponible en http://java.sun.com/javase/6/. Los cambios más importantes introducidos en esta versión son: • Incluye un nuevo marco de trabajo y APIs que hacen posible la combinación de Java con lenguajes dinámicos como PHP, Python, Ruby y JavaScript. • Incluye el motor Rhino, de Mozilla, una implementación de Javascript en Java. • Incluye un cliente completo de Servicios Web y soporta las últimas especificaciones para Servicios Web, como JAX-WS 2.0, JAXB 2.0, STAX y JAXP. • Mejoras en la interfaz gráfica y en el rendimiento.


54

CAPÍTULO 4. TIPOS DE LENGUAJES • Java SE 7 — Nombre clave Dolphin. En el año 2006 aún se encontraba en las primeras etapas de planificación. Su lanzamiento fue en julio de 2011. • Soporte para XML dentro del propio lenguaje. • Un nuevo concepto de superpaquete. • Soporte para closures. • Introducción de anotaciones estándar para detectar fallos en el software. • No oficiales: • NIO2. • Java Module System. • Java Kernel. • Nueva API para el manejo de Días y Fechas, la cual reemplazara las antiguas clases Date y Calendar. • Posibilidad de operar con clases BigDecimal usando operandos. • Java SE 8 — lanzada en marzo de 2014. Cabe destacar: • Incorpora de forma completa la librería JavaFX. • Diferentes mejoras en seguridad. • Diferentes mejoras en concurrencia. • Añade funcionalidad para programación funcional mediante expresiones Lambda. • Mejora la integración de JavaScript. • Nuevas API para manejo de fechas y tiempo (date - time).

En el 2005 se calcula en 4,5 millones el número de desarrolladores y 2.500 millones de dispositivos habilitados con tecnología Java.

4.2.2

Filosofía

El lenguaje Java se creó con cinco objetivos principales: 1. Debería usar el paradigma de la programación orientada a objetos. 2. Debería permitir la ejecución de un mismo programa en múltiples sistemas operativos. 3. Debería incluir por defecto soporte para trabajo en red. 4. Debería diseñarse para ejecutar código en sistemas remotos de forma segura. 5. Debería ser fácil de usar y tomar lo mejor de otros lenguajes orientados a objetos, como C++. Para conseguir la ejecución de código remoto y el soporte de red, los programadores de Java a veces recurren a extensiones como CORBA (Common Object Request Broker Architecture), Internet Communications Engine o OSGi respectivamente. Orientado a objetos La primera característica, orientado a objetos (“OO”), se refiere a un método de programación y al diseño del lenguaje. Aunque hay muchas interpretaciones para OO, una primera idea es diseñar el software de forma que los distintos tipos de datos que usen estén unidos a sus operaciones. Así, los datos y el código (funciones o métodos) se combinan en entidades llamadas objetos. Un objeto puede verse como un paquete que contiene el “comportamiento” (el código) y el “estado” (datos). El principio es separar aquello que cambia de las cosas que permanecen inalterables. Frecuentemente, cambiar una estructura de datos implica un cambio en el código que opera sobre los mismos, o viceversa. Esta separación en objetos coherentes e independientes ofrece una base más estable para el diseño de un


4.2. JAVA (LENGUAJE DE PROGRAMACIÓN)

55

sistema software. El objetivo es hacer que grandes proyectos sean fáciles de gestionar y manejar, mejorando como consecuencia su calidad y reduciendo el número de proyectos fallidos. Otra de las grandes promesas de la programación orientada a objetos es la creación de entidades más genéricas (objetos) que permitan la reutilización del software entre proyectos, una de las premisas fundamentales de la Ingeniería del Software. Un objeto genérico “cliente”, por ejemplo, debería en teoría tener el mismo conjunto de comportamiento en diferentes proyectos, sobre todo cuando estos coinciden en cierta medida, algo que suele suceder en las grandes organizaciones. En este sentido, los objetos podrían verse como piezas reutilizables que pueden emplearse en múltiples proyectos distintos, posibilitando así a la industria del software a construir proyectos de envergadura empleando componentes ya existentes y de comprobada calidad; conduciendo esto finalmente a una reducción drástica del tiempo de desarrollo. Podemos usar como ejemplo de objeto el aluminio. Una vez definidos datos (peso, maleabilidad, etc.), y su “comportamiento” (soldar dos piezas, etc.), el objeto “aluminio” puede ser reutilizado en el campo de la construcción, del automóvil, de la aviación, etc. La reutilización del software ha experimentado resultados dispares, encontrando dos dificultades principales: el diseño de objetos realmente genéricos es pobremente comprendido, y falta una metodología para la amplia comunicación de oportunidades de reutilización. Algunas comunidades de “código abierto” (open source) quieren ayudar en este problema dando medios a los desarrolladores para diseminar la información sobre el uso y versatilidad de objetos reutilizables y bibliotecas de objetos.

Independencia de la plataforma La segunda característica, la independencia de la plataforma, significa que programas escritos en el lenguaje Java pueden ejecutarse igualmente en cualquier tipo de hardware. Este es el significado de ser capaz de escribir un programa una vez y que pueda ejecutarse en cualquier dispositivo, tal como reza el axioma de Java, “write once, run anywhere”. Para ello, se compila el código fuente escrito en lenguaje Java, para generar un código conocido como “bytecode” (específicamente Java bytecode)—instrucciones máquina simplificadas específicas de la plataforma Java. Esta pieza está “a medio camino” entre el código fuente y el código máquina que entiende el dispositivo destino. El bytecode es ejecutado entonces en la máquina virtual (JVM), un programa escrito en código nativo de la plataforma destino (que es el que entiende su hardware), que interpreta y ejecuta el código. Además, se suministran bibliotecas adicionales para acceder a las características de cada dispositivo (como los gráficos, ejecución mediante hebras o threads, la interfaz de red) de forma unificada. Se debe tener presente que, aunque hay una etapa explícita de compilación, el bytecode generado es interpretado o convertido a instrucciones máquina del código nativo por el compilador JIT (Just In Time). Hay implementaciones del compilador de Java que convierten el código fuente directamente en código objeto nativo, como GCJ. Esto elimina la etapa intermedia donde se genera el bytecode, pero la salida de este tipo de compiladores sólo puede ejecutarse en un tipo de arquitectura. La licencia sobre Java de Sun insiste que todas las implementaciones sean “compatibles”. Esto dio lugar a una disputa legal entre Microsoft y Sun, cuando éste último alegó que la implementación de Microsoft no daba soporte a las interfaces RMI y JNI además de haber añadido características ‘’dependientes’’ de su plataforma. Sun demandó a Microsoft y ganó por daños y perjuicios (unos 20 millones de dólares) así como una orden judicial forzando la acatación de la licencia de Sun. Como respuesta, Microsoft no ofrece Java con su versión de sistema operativo, y en recientes versiones de Windows, su navegador Internet Explorer no admite la ejecución de applets sin un conector (o plugin) aparte. Sin embargo, Sun y otras fuentes ofrecen versiones gratuitas para distintas versiones de Windows. Las primeras implementaciones del lenguaje usaban una máquina virtual interpretada para conseguir la portabilidad. Sin embargo, el resultado eran programas que se ejecutaban comparativamente más lentos que aquellos escritos en C o C++. Esto hizo que Java se ganase una reputación de lento en rendimiento. Las implementaciones recientes de la JVM dan lugar a programas que se ejecutan considerablemente más rápido que las versiones antiguas, empleando diversas técnicas, aunque sigue siendo mucho más lento que otros lenguajes. La primera de estas técnicas es simplemente compilar directamente en código nativo como hacen los compiladores tradicionales, eliminando la etapa del bytecode. Esto da lugar a un gran rendimiento en la ejecución, pero tapa el camino a la portabilidad. Otra técnica, conocida como compilación JIT (Just In Time, o “compilación al vuelo”), convierte el bytecode a código nativo cuando se ejecuta la aplicación. Otras máquinas virtuales más sofisticadas usan una “recompilación dinámica” en la que la VM es capaz de analizar el comportamiento del programa en ejecución y recompila y optimiza las partes críticas. La recompilación dinámica puede lograr mayor grado de optimización que la compilación tradicional (o estática), ya que puede basar su trabajo en el conocimiento que de primera mano tiene sobre el entorno de ejecución y el conjunto de clases cargadas en memoria. La compilación JIT y la recompilación dinámica permiten a los programas Java aprovechar la velocidad de ejecución del código nativo sin por ello perder la


56

CAPÍTULO 4. TIPOS DE LENGUAJES

ventaja de la portabilidad en ambos. La portabilidad es técnicamente difícil de lograr, y el éxito de Java en ese campo ha sido dispar. Aunque es de hecho posible escribir programas para la plataforma Java que actúen de forma correcta en múltiples plataformas de distinta arquitectura, el gran número de estas con pequeños errores o inconsistencias llevan a que a veces se parodie el eslogan de Sun, "Write once, run anywhere" como “Write once, debug everywhere” (o “Escríbelo una vez, ejecútalo en cualquier parte” por “Escríbelo una vez, depúralo en todas partes”). El concepto de independencia de la plataforma de Java cuenta, sin embargo, con un gran éxito en las aplicaciones en el entorno del servidor, como los Servicios Web, los Servlets, los Java Beans, así como en sistemas empotrados basados en OSGi, usando entornos Java empotrados. El recolector de basura En Java el problema fugas de memoria se evita en gran medida gracias a la recolección de basura (o automatic garbage collector). El programador determina cuándo se crean los objetos y el entorno en tiempo de ejecución de Java (Java runtime) es el responsable de gestionar el ciclo de vida de los objetos. El programa, u otros objetos pueden tener localizado un objeto mediante una referencia a éste. Cuando no quedan referencias a un objeto, el recolector de basura de Java borra el objeto, liberando así la memoria que ocupaba previniendo posibles fugas (ejemplo: un objeto creado y únicamente usado dentro de un método sólo tiene entidad dentro de éste; al salir del método el objeto es eliminado). Aun así, es posible que se produzcan fugas de memoria si el código almacena referencias a objetos que ya no son necesarios—es decir, pueden aún ocurrir, pero en un nivel conceptual superior. En definitiva, el recolector de basura de Java permite una fácil creación y eliminación de objetos y mayor seguridad.

4.2.3

Sintaxis

La sintaxis de Java se deriva en gran medida de C++. Pero a diferencia de éste, que combina la sintaxis para programación genérica, estructurada y orientada a objetos, Java fue construido desde el principio para ser completamente orientado a objetos. Todo en Java es un objeto (salvo algunas excepciones), y todo en Java reside en alguna clase (recordemos que una clase es un molde a partir del cual pueden crearse varios objetos). Aplicaciones autónomas

Este ejemplo necesita una pequeña explicación.

• Todo en Java está dentro de una clase, incluyendo programas autónomos. • El código fuente se guarda en archivos con el mismo nombre que la clase que contienen y con extensión “.java”. Una clase (class) declarada pública (public) debe seguir este convenio. En el ejemplo anterior, la clase es Hola, por lo que el código fuente debe guardarse en el fichero “Hola.java” • El compilador genera un archivo de clase (con extensión “.class”) por cada una de las clases definidas en el archivo fuente. Una clase anónima se trata como si su nombre fuera la concatenación del nombre de la clase que la encierra, el símbolo “$”, y un número entero. • Los programas que se ejecutan de forma independiente y autónoma, deben contener el método ”main()”. • La palabra reservada ”void” indica que el método main no devuelve nada. • El método main debe aceptar un array de objetos tipo String. Por acuerdo se referencia como ”args”, aunque puede emplearse cualquier otro identificador. • La palabra reservada ”static” indica que el método es un método de clase, asociado a la clase en vez de a una instancia de la misma. El método main debe ser estático o ’’de clase’’. • La palabra reservada public significa que un método puede ser llamado desde otras clases, o que la clase puede ser usada por clases fuera de la jerarquía de la propia clase. Otros tipos de acceso son ”private” o ”protected”. • La utilidad de impresión (en pantalla por ejemplo) forma parte de la biblioteca estándar de Java: la clase ‘’’System’’’ define un campo público estático llamado ‘’’out’’’. El objeto out es una instancia de ‘’’PrintStream’’’, que ofrece el método ‘’’println (String)’’’ para volcar datos en la pantalla (la salida estándar).


4.2. JAVA (LENGUAJE DE PROGRAMACIÓN)

57

• Las aplicaciones autónomas se ejecutan dando al entorno de ejecución de Java el nombre de la clase cuyo método main debe invocarse. Por ejemplo, una línea de comando (en Unix o Windows) de la forma java – cp . Hola ejecutará el programa del ejemplo (previamente compilado y generado “Hola.class”). El nombre de la clase cuyo método main se llama puede especificarse también en el fichero “MANIFEST” del archivo de empaquetamiento de Java (.jar). Applets Las applet Java son programas incrustados en otras aplicaciones, normalmente una página Web que se muestra en un navegador. // Hello.java import javax.swing.JApplet; import java.awt.Graphics; public class Hello extends JApplet { public void paint(Graphics g) { g.drawString(“Hola, mundo!", 65, 95); } } <!-- Hola.html --> <html> <head> <title>Applet Hola Caracola.</title> </head> <body> <applet code="Hola.class” width="200” height="200"> </applet> </body> </html> Actualmente HTML 5 ha eliminado el uso de la etiqueta <applet>. Pero todavía existe la forma de usarlo en HTML5. (Texto en inglés) Java Applets in HTML5. La sentencia import indica al compilador de Java que incluya las clases java.applet. Applet y java.awt. Graphics, para poder referenciarlas por sus nombres, sin tener que anteponer la ruta completa cada vez que se quieran usar en el código fuente. La clase Hola extiende (extends) a la clase Applet, es decir, es una subclase de ésta. La clase Applet permite a la aplicación mostrar y controlar el estado del applet. La clase Applet es un componente del AWT (Abstract Window Toolkit), que permite al applet mostrar una interfaz gráfica de usuario o GUI (Graphical User Interface), y responder a eventos generados por el usuario. La clase Hola sobrecarga el método paint (Graphics) heredado de la superclase contenedora (Applet en este caso), para acceder al código encargado de dibujar. El método paint() recibe un objeto Graphics que contiene el contexto gráfico para dibujar el applet. El método paint() llama al método drawString (String, int, int) del objeto Servlets Los servlets son componentes de la parte del servidor de Java EE, encargados de generar respuestas a las peticiones recibidas de los clientes. // Hola.java import java.io.IOException; import javax.servlet.*; public class Hola extends GenericServlet { public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { response.setContentType(“text/html”); PrintWriter pw = response.getWriter(); pw.println(“Hola, mundo!"); pw.close(); } } Las sentencias import indican al compilador de Java la inclusión de todas las clases públicas e interfaces de los paquetes java.io y javax.servlet en la compilación. La clase Hola extiende (extends), es heredera de la clase GenericServlet. Esta clase proporciona la interfaz para que el servidor le pase las peticiones al servlet y el mecanismo para controlar el ciclo de vida del servlet. La clase Hola sobrecarga el método service (ServletRequest, ServletResponse), definido por la interfaz servlet para acceder al manejador de la petición de servicio. El método service() recibe un objeto de tipo ServletRequest que contiene la petición del cliente y un objeto de tipo ServletResponse, usado para generar la respuesta que se devuelve al cliente. El método service() puede lanzar (throws) excepciones de tipo ServletException e IOException si ocurre algún tipo de anomalía. El método setContentType (String) en el objeto respuesta establece el tipo de contenido MIME a “text/html”, para indicar al cliente que la respuesta a su petición es una página con formato HTML. El método getWriter() del objeto respuesta devuelve un objeto de tipo PrintWriter, usado como una tubería por la que viajarán los datos al cliente. El método println (String) escribe la cadena “Hola, mundo!" en la respuesta y finalmente se llama al método close() para cerrar la conexión, que hace que los datos escritos en la tubería o stream sean devueltos al cliente. Aplicaciones con ventanas Java SE.

Swing es la biblioteca para la interfaz gráfica de usuario avanzada de la plataforma

// Hola.java import javax.swing.*; public class Hola extends JFrame { Hola() { setDefaultCloseOperation(WindowConstants.DISPOSE_ add(new JLabel(“Hola, mundo!")); pack(); } public static void main(String[] args) { new Hola().setVisible(true); } }


58

CAPÍTULO 4. TIPOS DE LENGUAJES

Las instrucciones import indican al compilador de Java que las clases e interfaces del paquete javax.swing se incluyan en la compilación. La clase Hola extiende (extends) la clase javax.swing.JFrame, que implementa una ventana con una barra de título y un control para cerrarla. El constructor Hola() inicializa el marco o frame llamando al método setDefaultCloseOperation (int) heredado de JFrame para establecer las operaciones por defecto cuando el control de cierre en la barra de título es seleccionado al valor WindowConstants.DISPOSE_ON_CLOSE. Esto hace que se liberen los recursos tomados por la ventana cuando es cerrada, y no simplemente ocultada, lo que permite a la máquina virtual y al programa acabar su ejecución. A continuación se crea un objeto de tipo JLabel con el texto “Hola, mundo!", y se añade al marco mediante el método add (Component), heredado de la clase Container. El método pack(), heredado de la clase Window, es invocado para dimensionar la ventana y distribuir su contenido. El método main() es llamado por la JVM al comienzo del programa. Crea una instancia de la clase Hola y hace la ventana sea mostrada invocando al método setVisible (boolean) de la superclase (clase de la que hereda) con el parámetro a true. Véase que, una vez el marco es dibujado, el programa no termina cuando se sale del método main(), ya que el código del que depende se encuentra en un hilo de ejecución independiente ya lanzado, y que permanecerá activo hasta que todas las ventanas hayan sido destruidas.

4.2.4

Entornos de funcionamiento

El diseño de Java, su robustez, el respaldo de la industria y su fácil portabilidad han hecho de Java uno de los lenguajes con un mayor crecimiento y amplitud de uso en distintos ámbitos de la industria de la informática.

En dispositivos móviles y sistemas embebidos Desde la creación de la especificación J2ME (Java 2 Platform, Micro Edition), una versión del entorno de ejecución Java reducido y altamente optimizado, especialmente desarrollado para el mercado de dispositivos electrónicos de consumo se ha producido toda una revolución en lo que a la extensión de Java se refiere. Es posible encontrar microprocesadores diseñados para ejecutar bytecode Java y software Java para tarjetas inteligentes (JavaCard), teléfonos móviles, buscapersonas, set-top-boxes, sintonizadores de TV y otros pequeños electrodomésticos. El modelo de desarrollo de estas aplicaciones es muy semejante a las applets de los navegadores salvo que en este caso se denominan MIDlets. Véase Sun Mobile Device Tecnology

En el navegador web Desde la primera versión de java existe la posibilidad de desarrollar pequeñas aplicaciones (Applets) en Java que luego pueden ser incrustadas en una página HTML para que sean descargadas y ejecutadas por el navegador web. Estas mini-aplicaciones se ejecutan en una JVM que el navegador tiene configurada como extensión (plug-in) en un contexto de seguridad restringido configurable para impedir la ejecución local de código potencialmente malicioso. El éxito de este tipo de aplicaciones (la visión del equipo de Gosling) no fue realmente el esperado debido a diversos factores, siendo quizás el más importante la lentitud y el reducido ancho de banda de las comunicaciones en aquel entonces que limitaba el tamaño de las applets que se incrustaban en el navegador. La aparición posterior de otras alternativas (aplicaciones web dinámicas de servidor) dejó un reducido ámbito de uso para esta tecnología, quedando hoy relegada fundamentalmente a componentes específicos para la intermediación desde una aplicación web dinámica de servidor con dispositivos ubicados en la máquina cliente donde se ejecuta el navegador. Las applets Java no son las únicas tecnologías (aunque sí las primeras) de componentes complejos incrustados en el navegador. Otras tecnologías similares pueden ser: ActiveX de Microsoft, Flash, Java Web Start, etc.


4.2. JAVA (LENGUAJE DE PROGRAMACIÓN)

59

En sistemas de servidor En la parte del servidor, Java es más popular que nunca, desde la aparición de la especificación de Servlets y JSP (Java Server Pages). Hasta entonces, las aplicaciones web dinámicas de servidor que existían se basaban fundamentalmente en componentes CGI y lenguajes interpretados. Ambos tenían diversos inconvenientes (fundamentalmente lentitud, elevada carga computacional o de memoria y propensión a errores por su interpretación dinámica). Los servlets y las JSPs supusieron un importante avance ya que: • El API de programación es muy sencilla, flexible y extensible. • Los servlets no son procesos independientes (como los CGIs) y por tanto se ejecutan dentro del mismo proceso que la JVM mejorando notablemente el rendimiento y reduciendo la carga computacional y de memoria requeridas. • Las JSPs son páginas que se compilan dinámicamente (o se pre-compilan previamente a su distribución) de modo que el código que se consigue supone una ventaja en rendimiento substancial frente a muchos lenguajes interpretados. La especificación de Servlets y JSPs define un API de programación y los requisitos para un contenedor (servidor) dentro del cual se puedan desplegar estos componentes para formar aplicaciones web dinámicas completas. Hoy día existen multitud de contenedores (libres y comerciales) compatibles con estas especificaciones. A partir de su expansión entre la comunidad de desarrolladores, estas tecnologías han dado paso a modelos de desarrollo mucho más elaborados con frameworks (pe Struts, Webwork) que se sobreponen sobre los servlets y las JSPs para conseguir un entorno de trabajo mucho más poderoso y segmentado en el que la especialización de roles sea posible (desarrolladores, diseñadores gráficos,...) y se facilite la reutilización y robustez de código. A pesar de todo ello, las tecnologías que subyacen (Servlets y JSPs) son substancialmente las mismas. Este modelo de trabajo se ha convertido en uno de los estándar de-facto para el desarrollo de aplicaciones web dinámicas de servidor. En aplicaciones de escritorio Hoy en día existen multitud de aplicaciones gráficas de usuario basadas en Java. El entorno de ejecución Java (JRE) se ha convertido en un componente habitual en los PC de usuario de los sistemas operativos más usados en el mundo. Además, muchas aplicaciones Java lo incluyen dentro del propio paquete de la aplicación de modo que se ejecuten en cualquier PC. En las primeras versiones de la plataforma Java existían importantes limitaciones en las APIs de desarrollo gráfico (AWT). Desde la aparición de la biblioteca Swing la situación mejoró substancialmente y posteriormente con la aparición de bibliotecas como SWT hacen que el desarrollo de aplicaciones de escritorio complejas y con gran dinamismo, usabilidad, etc. sea relativamente sencillo. Plataformas soportadas Una versión del entorno de ejecución Java JRE (Java Runtime Environment) está disponible en la mayoría de equipos de escritorio. Sin embargo, Microsoft no lo ha incluido por defecto en sus sistemas operativos. En el caso de Apple, éste incluye una versión propia del JRE en su sistema operativo, el Mac OS. También es un producto que por defecto aparece en la mayoría de las distribuciones de GNU/Linux. Debido a incompatibilidades entre distintas versiones del JRE, muchas aplicaciones prefieren instalar su propia copia del JRE antes que confiar su suerte a la aplicación instalada por defecto. Los desarrolladores de applets de Java o bien deben insistir a los usuarios en la actualización del JRE, o bien desarrollar bajo una versión antigua de Java y verificar el correcto funcionamiento en las versiones posteriores.

4.2.5

Programación


60

CAPÍTULO 4. TIPOS DE LENGUAJES

Expresiones Las expresiones son un conjunto de elementos o tokens junto con literales que son evaluados para devolver un resultado. Los tokens son elemento más pequeño de un programa que es significativo, e interpretado o entendido por el compilador, en java los tokens se dividen en cinco categorías que son: Identificadores: Son las representaciones que se les da a los nombres que se asignan a las variables, clases, paquetes, métodos y constantes en el código de java para que el compilador los identifique y el programador pueda entenderlos. En java los identificadores pueden diferenciar entre mayúsculas o minúsculas por ser case sensitive, por lo que la variable cuyo nombre sea “Mivariable”, no es igual a “mivariable”, ya que java identifica estas como variables diferentes por el case sensitive, también se puede utilizar números, o el signo “_” para asignar un identificador. Palabras claves: Son los identificadores reservados por java para cumplir con un objetivo específico en el código y el compilador, se usan de forma limitada y en casos específicos. Las palabras claves que usa java son las siguientes: Las palabras que se encuentran en negrilla, son palabras claves para java aunque actualmente no se utilicen en la versión de java, pero se pretenden integrar en las siguientes versiones de java. Literales y constantes: Los literales son sintaxis para asignar valores a una variable, es decir el valor que puede tomar una variable, también es un valor constante que puede ser de tipo numérico. Las constantes son variables que tienen un valor fijo y no puede ser modificado en el trascurso de la ejecución del código, estas se declaran por medio de los modificadores final y static. final static double pi= 3.1416; Operadores: Son los que nos indican una evaluación que se aplica a un objeto o un dato, sobre un identificador o constante. Un ejemplo de operadores puede ser la suma, resta o multiplicación. Separadores: Se utilizan para indicarle al compilador de java donde se ubican los elementos del código, los separadores que admite java son: { },:; También el compilador de java identifica y elimina los comentarios, retornos de carros espacios vacíos y de tabulación a la hora de compilar por lo que no son considerados parte de un token. Las expresiones pueden ser una combinación en secuencia de variables, operadores y métodos. Las expresiones son utilizadas para realizar cálculos, para asignar valores a variables, o para controlar la ejecución del flujo del programa. Operadores Los operadores son aquellos que tras realizar una operación devuelven un resultado, estos se puede caracterizar por el número de operadores, el tipo de operandos, y el resultado que generan. Número de operandos. Pueden ser de dos tipos unarios, y binarios. Los unarios son aquellos que solo necesitan de un operando para devolver un valor, mientras que los binarios necesitan de dos o más operandos. Operadores unarios. Operadores binarios. Operadores a nivel de bit

Los operadores a nivel de bit nos permiten realizar operaciones sobre números binarios.

~ Complemento a 1, este operador invierte los dígitos, cambiando los 0 por 1 y los 1 por 0, un ejemplo puede ser: 11001011 ~ 11001011 resultado 00110100 Como se puede ver se cambian los valores de 0 a 1 y de 1 a 0. & AND a nivel de bit, este operador realiza una operación AND o suma entre dos números de bit, en donde si dos bit son igual a 1 el resultado será 1, de lo contrario será 0, un ejemplo puede ser: situacion 01001101 & 10011011 ______________ 00001001 | Or a nivel de bit, este operador realiza una operación OR en donde si alguno de los dos números es 1 el resultado será 1, un ejemplo puede ser: 11001101 | 01011101 ______________ 11011101 ^ XOR a nivel de bit, este operador realiza la operación XOR en donde si los dos números son iguales el resultado será


4.2. JAVA (LENGUAJE DE PROGRAMACIÓN)

61

0 de lo contrario será 1, un ejemplo puede ser: 00101001 ^ 01101101 ______________ 01000100 << Desplazamiento a la izquierda, este operador desplaza n cantidad de espacios a la izquierda un bit, un ejemplo puede ser; 01101110 01101110 << 1 = 11011100 Como se puede ver al realizar el desplazamiento se realiza una inserción de un dígito 0 a la derecha

Precedencia de operadores Los operadores son una parte principal en las expresiones, el tipo y forma de uso es fundamental a la hora de programas, pero para su uso se tiene que tener en cuenta una serie de normas, como lo son la precedencia de los operadores. Los operadores son ejecutados según su precedencia, si cuentan con una precedencia mayor serán evaluados primero que los de precedencia menor, si por casualidad se llegase a presentar operadores con el mismo nivel de precedencia, estos se evaluaran de derecha a izquierda, si son operadores binarios (menos los operadores de asignación) se evaluaran de izquierda a derecha. A Java se le puede indicar qué operadores debe evaluar primero sin importar su precedencia por medio de paréntesis ( ), de esta forma el compilador de java interpreta que primero ejecutara las operaciones que se encuentran dentro de los paréntesis, y luego continuara con los demás operadores. La siguiente tabla indicara en nivel de precedencia de los operadores utilizados en java, teniendo en cuenta que el nivel de precedencia está indicado de arriba a abajo, siendo arriba el nivel más alto. Precedencia de los operadores en java. Un ejemplo de la precedencia de los operadores en java podría ser el siguiente, en donde tenemos un código que se encargará de realizar una serie de operaciones aritméticas. int numero1 = 3; int numero2 = 4; int resultado; resultado = numero1 + numero2 * 3; System.out.println (resultado); //esto imprime el valor de 15 según la precedencia de los operadores la multiplicación * tiene mayor prioridad que la suma +, por lo que primero se ejecuta la multiplicación y luego se realiza la suma. int numero1 = 3; int numero2 = 4; int resultado; resultado = (numero1 + numero2) * 3; System.out.println (resultado); //esto imprime el valor de 21 En este caso el resultado cambia ya que primero se evalúan los parámetros que están dentro del paréntesis y luego se evalúa el resto de parámetros. Una de las recomendaciones que da java para el desarrollo es el uso de los paréntesis en las operaciones con más de 3 operandos, así de esta forma el código se hace más legible y se evitan errores al momento de compilar.

Sentencias Las sentencias son una representación de una secuencia de acciones que se realizan en java, la clave fundamental de las sentencias es su punto final que indica que ha finalizado la sentencia y puede continuar con la siguiente, el indicador utilizado es el signo de punto y coma (;). Contamos en java con sentencias que pueden ir desde sentencias de asignación, de bucles, condicionales, y de salto. Las sentencias se conforman comúnmente por una instancia, y un operador, un ejemplo es la sentencia de asignación que se conforma por una instancia de una variable, el signo de asignación y una expresión, un ejemplo es: int variable = 12+2; Las sentencias de asignación son aquellas en las que se asigna un valor a una variable o constante. Las sentencias condicionales son las que expresan una condición para definir el flujo de ejecución del programa, entre ellas tenemos if-else y switch. Las sentencias de bucles se encargar de realizar una acción cierta cantidad de tiempo dado, o hasta que se cumpla con una condición, entre ellas tenemos el while, do-while, y for. Las sentencias de salto llevan al compilador a un punto específico del programa o hacia la siguiente sentencia de ejecución, entre ellas tenemos break, continue, y return.


62

CAPÍTULO 4. TIPOS DE LENGUAJES

Conversión de tipos En algunos casos suele ser necesario convertir un tipo de dato a otro, esto se le conoce como conversión de tipos, modelado, o tipado, así de esta forma poder realizar las operaciones necesarias sobre el valor que se desea convertir. Se debe tener en cuenta el tipo de dato que se va a convertir, ya que si se convierte un dato que tenga una cantidad menor de bit al anterior este tendrá perdida de información, un ejemplo de tipado puede ser un número long que se desea convertir a int, el compilador eliminara los primeros 32bit del long para ajustarlo al int ya que el int es de 32bit y el long de 64. Si la conversión se realiza a un tipo de datos de menos bit a un tipo de datos con mayor bit, la conversión se realiza automáticamente llamada conversión implícita, pero si se realiza de un tipo de datos con mayor bit a menor bit se tiene que realizar una conversión explícita, la cual se realiza con un casting, al usar este método se obliga a realizar la conversión por lo cual puede haber perdida de datos en la conversión. Para realizar una conversión explícita se tiene que poner el tipo de dato que se desea realizar la conversión entre paréntesis, luego el valor o la variable que se desea convertir. Un ejemplo de conversión de tipo explícito puede ser: Int numero1 = 32; byte numero2; numero2 = (byte) numero1; Un ejemplo de una conversión de tipo implícita puede ser: int numero1 = 32; long numero2; numero2 = numero1; Las siguiente tabla muestra la los tipos de datos que se pueden realizar una conversión implícita desde el dato origen, hasta el dato destino que es el dato en el que se va a convertir. Los tipos de datos booleanos no pueden ser convertidos a otro tipo de datos, por ningún método mencionado anteriormente. Otro tipo de conversión que no se encuentre en esta tabla desde el origen al destino, tiene que realizarse por medio de una conversión explícita por casting. Cuando se desea realizar una conversión de un tipo string como origen a otro tipo, es necesario utilizar una función que se encarga de convertir el tipo de dato, la función necesaria se compone de la variable que va almacenar el resultado, y dependiendo de la variable se usa el parámetro que inicia con el tipo de dato a convertir, Integer, Byte, Short, o Long, seguida de punto “. “, el cual indica que se cargarán los atributos del parámetro, en donde cargaremos el parseInt si queremos convertir a interger o parseByte si queremos convertir a byte, o dependiendo del tipo de dato, seguido de paréntesis en donde se agregara el valor de string a convertir. Algunos ejemplos puede ser: int numero1; long numero2; byte numero3; String texto= “2013”; numero1 = Integer.parseInt ( texto ); numero2 = Long.parseLong ( texto); numero3 = Byte.parseByte ( texto ); esto suele ser usado para realizar una conversión de texto cuando se ingresan valores numéricos por una entrada a java, la cual los detecta como string, así de esta forma puede convertir el texto que se ingresa a un número para realizar operaciones, como una calculadora.

4.2.6

Industria relacionada

Sun Microsystem, como creador del lenguaje de programación Java y de la plataforma JDK, mantiene fuertes políticas para mantener una especificación del lenguaje[5] así como de la máquina virtual[6] a través del JCP. Es debido a este esfuerzo que se mantiene un estándar de facto. Son innumerables las compañías que desarrollan aplicaciones para Java y/o están volcadas con esta tecnología: • La industria de la telefonía móvil está fuertemente influenciada por la tecnología Java. • Los entornos de desarrollo Netbeans y Eclipse ha tomado un lugar importante entre la comunidad de desarrolladores Java. • La fundación Apache tiene también una presencia importante en el desarrollo de bibliotecas y componentes de servidor basados en Java. • IBM, BEA, IONA, Oracle,... son empresas con grandes intereses y productos creados en y para Java.

4.2.7

Críticas

En 1995 alguien dijo que Java fue creado para abrir una nueva vía en la gestión de software complejo, y es por regla general aceptado que se ha comportado bien en ese aspecto. Sin embargo no puede decirse que Java no tenga grietas,


4.2. JAVA (LENGUAJE DE PROGRAMACIÓN)

63

ni que se adapta completamente a todos los estilos de programación, todos los entornos, o todas las necesidades. General • Java no ha aportado capacidades estándares para aritmética en punto flotante. El estándar IEEE 754 para “Estándar para Aritmética Binaria en Punto Flotante” apareció en 1985, y desde entonces es el estándar para la industria. Y aunque la aritmética flotante de Java (cosa que cambió desde el 13 de noviembre de 2006, cuando se abrió el código fuente y se adoptó la licencia GPL, aparte de la ya existente)[cita requerida] se basa en gran medida en la norma del IEEE, no soporta aún algunas características. Más información al respecto puede encontrarse en la sección final de enlaces externos. El lenguaje • En un sentido estricto, Java no es un lenguaje absolutamente orientado a objetos, a diferencia de, por ejemplo, Ruby o Smalltalk. Por motivos de eficiencia, Java ha relajado en cierta medida el paradigma de orientación a objetos, y así por ejemplo, no todos los valores son objetos. • El código Java puede ser a veces redundante en comparación con otros lenguajes. Esto es en parte debido a las frecuentes declaraciones de tipos y conversiones de tipo manual (casting). También se debe a que no se dispone de operadores sobrecargados, y a una sintaxis relativamente simple. Sin embargo, J2SE 5.0 introduce elementos para tratar de reducir la redundancia, como una nueva construcción para los bucles ‘’’foreach’’’. • A diferencia de C++, Java no dispone de operadores de sobrecarga definidos por el usuario. Los diseñadores de Java tomaron esta decisión puesto que consideraban que, bajo ciertas circunstancias, esta característica podía complicar la lectura y mantenimiento de los programas. Apariencia La apariencia externa (el ‘‘‘look and feel’’’) de las aplicaciones GUI (Graphical User Interface) escritas en Java usando la plataforma Swing difiere a menudo de la que muestran aplicaciones nativas. Aunque el programador puede usar el juego de herramientas AWT (Abstract Windowing Toolkit) que genera objetos gráficos de la plataforma nativa, el AWT no es capaz de funciones gráficas avanzadas sin sacrificar la portabilidad entre plataformas; ya que cada una tiene un conjunto de APIs distinto, especialmente para objetos gráficos de alto nivel. Las herramientas de Swing, escritas completamente en Java, evitan este problema construyendo los objetos gráficos a partir de los mecanismos de dibujo básicos que deben estar disponibles en todas las plataformas. El inconveniente es el trabajo extra requerido para conseguir la misma apariencia de la plataforma destino. Aunque esto es posible (usando GTK+ y el Look-andFeel de Windows), la mayoría de los usuarios no saben cómo cambiar la apariencia que se proporciona por defecto por aquella que se adapta a la de la plataforma. Rendimiento El bytecode de Java puede ser interpretado en tiempo de ejecución por la máquina virtual, o bien compilado al cargarse el programa, o durante la propia ejecución, para generar código nativo que se ejecuta directamente sobre el hardware. Si es interpretado, será más lento que usando el código máquina intrínseco de la plataforma destino. Si es compilado, durante la carga inicial o la ejecución, la penalización está en el tiempo necesario para llevar a cabo la compilación. Algunas características del propio lenguaje conllevan una penalización en tiempo, aunque no son únicas de Java. Algunas de ellas son el chequeo de los límites de arrays, chequeo en tiempo de ejecución de tipos, y la indirección de funciones virtuales. El uso de un recolector de basura para eliminar de forma automática aquellos objetos no requeridos, añade una sobrecarga que puede afectar al rendimiento, o ser apenas apreciable, dependiendo de la tecnología del recolector y de la aplicación en concreto. Las JVM modernas usan recolectores de basura que gracias a rápidos algoritmos de manejo de memoria, consiguen que algunas aplicaciones puedan ejecutarse más eficientemente. El rendimiento entre un compilador JIT y los compiladores nativos puede ser parecido, aunque la distinción no está clara en este punto. La compilación mediante el JIT puede consumir un tiempo apreciable, un inconveniente principalmente para aplicaciones de corta duración o con gran cantidad de código. Sin embargo, una vez compilado, el


64

CAPÍTULO 4. TIPOS DE LENGUAJES

rendimiento del programa puede ser comparable al que consiguen compiladores nativos de la plataforma destino, inclusive en tareas numéricas. Aunque Java no permite la expansión manual de llamadas a métodos, muchos compiladores JIT realizan esta optimización durante la carga de la aplicación y pueden aprovechar información del entorno en tiempo de ejecución para llevar a cabo transformaciones eficientes durante la propia ejecución de la aplicación. Esta recompilación dinámica, como la que proporciona la máquina virtual HotSpot de Sun, puede llegar a mejorar el resultado de compiladores estáticos tradicionales, gracias a los datos que sólo están disponibles durante el tiempo de ejecución. Java fue diseñado para ofrecer seguridad y portabilidad, y no ofrece acceso directo al hardware de la arquitectura ni al espacio de direcciones. Java no soporta expansión de código ensamblador, aunque las aplicaciones pueden acceder a características de bajo nivel usando bibliotecas nativas (JNI, Java Native Interfaces).

4.2.8

Recursos

JRE El JRE (Java Runtime Environment, o Entorno en Tiempo de Ejecución de Java) es el software necesario para ejecutar cualquier aplicación desarrollada para la plataforma Java. El usuario final usa el JRE como parte de paquetes software o plugins (o conectores) en un navegador Web. Sun ofrece también el SDK de Java 2, o JDK (Java Development Kit) en cuyo seno reside el JRE, e incluye herramientas como el compilador de Java, Javadoc para generar documentación o el depurador. Puede también obtenerse como un paquete independiente, y puede considerarse como el entorno necesario para ejecutar una aplicación Java, mientras que un desarrollador debe además contar con otras facilidades que ofrece el JDK. Componentes • Bibliotecas de Java, que son el resultado de compilar el código fuente desarrollado por quien implementa la JRE, y que ofrecen apoyo para el desarrollo en Java. Algunos ejemplos de estas bibliotecas son: • Las bibliotecas centrales, que incluyen: • Una colección de bibliotecas para implementar estructuras de datos como listas, arrays, árboles y conjuntos. • Bibliotecas para análisis de XML. • Seguridad. • Bibliotecas de internacionalización y localización. • Bibliotecas de integración, que permiten la comunicación con sistemas externos. Estas bibliotecas incluyen: • La API para acceso a bases de datos JDBC (Java DataBase Conectivity). • La interfaz JNDI (Java Naming and Directory Interface) para servicios de directorio. • RMI (Remote Method Invocation) y CORBA para el desarrollo de aplicaciones distribuidas. • Bibliotecas para la interfaz de usuario, que incluyen: • El conjunto de herramientas nativas AWT (Abstract Window Toolkit), que ofrece componentes GUI (Graphical User Interface), mecanismos para usarlos y manejar sus eventos asociados. • Las Bibliotecas de Swing, construidas sobre AWT pero ofrecen implementaciones no nativas de los componentes de AWT. • APIs para la captura, procesamiento y reproducción de audio. • Una implementación dependiente de la plataforma en que se ejecuta de la máquina virtual de Java (JVM), que es la encargada de la ejecución del código de las bibliotecas y las aplicaciones externas. • Plugins o conectores que permiten ejecutar applets en los navegadores Web. • Java Web Start, para la distribución de aplicaciones Java a través de Internet. • Documentación y licencia.


4.2. JAVA (LENGUAJE DE PROGRAMACIÓN)

65

APIs Sun define tres plataformas en un intento por cubrir distintos entornos de aplicación. Así, ha distribuido muchas de sus APIs (Application Program Interface) de forma que pertenezcan a cada una de las plataformas: • Java ME (Java Platform, Micro Edition) o J2ME — orientada a entornos de limitados recursos, como teléfonos móviles, PDAs (Personal Digital Assistant), etc. • Java SE (Java Platform, Standard Edition) o J2SE — para entornos de gama media y estaciones de trabajo. Aquí se sitúa al usuario medio en un PC de escritorio. • Java EE (Java Platform, Enterprise Edition) o J2EE — orientada a entornos distribuidos empresariales o de Internet. Las clases en las APIs de Java se organizan en grupos disjuntos llamados paquetes. Cada paquete contiene un conjunto de interfaces, clases y excepciones relacionadas. La información sobre los paquetes que ofrece cada plataforma puede encontrarse en la documentación de ésta. El conjunto de las APIs es controlado por Sun Microsystems junto con otras entidades o personas a través del programa JCP (Java Community Process). Las compañías o individuos participantes del JCP pueden influir de forma activa en el diseño y desarrollo de las APIs, algo que ha sido motivo de controversia. Extensiones y arquitecturas relacionadas Las extensiones[7] de Java están en paquetes que cuelgan de la raíz javax: javax.*. No se incluyen en la JDK o el JRE. Algunas de las extensiones y arquitecturas ligadas estrechamente al lenguaje Java son: • Java EE (Java Platform, Enterprise Edition; antes J2EE) —para aplicaciones distribuidas orientadas al entorno empresarial

4.2.9

Java en código abierto

Java se ha convertido en un lenguaje con una implantación masiva en todos los entornos (personales y empresariales). El control que mantiene Sun sobre éste ha generado reticencias en la comunidad de empresas con fuertes intereses en Java (IBM, Oracle) y obviamente en la comunidad de desarrolladores de software libre. La evolución basada en un comité en el que participen todos los implicados no es suficiente y la comunidad demandaba desde hace tiempo la liberación de las APIs y bibliotecas básicas de la JDK. En diciembre de 2006, Sun Microsystems comenzó el relanzamiento de su plataforma Java[8] bajo la licencia GPL de GNU. En abril de 2009 Oracle adquirió Sun Microsystems, lo que generó temor en la comunidad ante la posible mercantilización del lenguaje de programación orientado a objetos más popular actualmente. Por ahora Oracle ha seguido manteniendo Java, estando las versiones posteriores a la 6 bajo su control. Se instala una versión homebrew de PSPKVM (0.5.5) para emular la plataforma de Java en PSP. Esto permite usar programas JAVA en esta videoconsola. Alternativas libres Existen alternativas para el entorno de ejecución y de desarrollo de Java con una gran cobertura de funcionalidades con respecto a las implementaciones comerciales de Sun, IBM, Bea, etc. Críticas referentes a Java y el software libre • Free But Shackled — The Java Trap, de Richard Stallman, 12 de abril de 2004. (respuesta de James Gosling) • Traducción al español de este artículo: Libre pero encadenado. La trampa del Java. (Nótese que hay una nota en un recuadro amarillo que habla de la situación actual con respecto a lo que se dice en ese artículo)


66

CAPÍTULO 4. TIPOS DE LENGUAJES

Notar que este artículo fue escrito antes de la liberación del código fuente de Java. En la actualidad la postura de la Free Software Foundation y de Richard Stallman han cambiado[cita requerida] , mostrándose partidarios ambos de su uso en software libre.

4.2.10

Véase también

• Applet Java • Drupal • JavaOne • JavaOS • Javapedia • Java Community Process • Java User Group • Máquina virtual Java • OpenJDK • Plataforma Java

4.2.11

Referencias

• Jon Byous, Java technology: The early years. Sun Developer Network, sin fecha[ca. 1998]. Recuperado 21 de abril de 2005. • James Gosling, A brief history of the Green project. Java.net, sin fecha [ca. Q1/1998]. Recuperado 22 de abril de 2005. • James Gosling, Bill Joy, Guy Steele, y Gilad Bracha, The Java language specification, tercera edición. AddisonWesley, 2005. ISBN 0-321-24678-0. • Tim Lindholm y Frank Yellin. The Java Virtual Machine specification, segunda edición. Addison-Wesley, 1999. ISBN 0-201-43294-3.

4.2.12

Notas

[1] «Programming Language Popularity». 2009. Archivado desde el original el 29 de noviembre de 2015. Consultado el 16 de enero de 2009. [2] «TIOBE Programming Community Index». 2009. Consultado el 6 de mayo de 2009. [3] «Jonathan Schwartz’s Blog: Different Isn't Always Better, But Better’s Always Different». Blogs.sun.com. Consultado el 24 de septiembre de 2010. [4] M. Domínguez-Dorado,. Todo Programación. Nº 8. Págs. 39-42. Editorial Iberprensa (Madrid). DL M-13679-2004. Febrero, 2005. Dibujando sobre lienzos en Java. [5] Especificación del lenguaje Java [6] Especificación de la máquina virtual Java [7] M. Domínguez-Dorado, Guillermo Som. Todo Programación. Nº 11. Págs. 10-20. Editorial Iberprensa (Madrid). DL M13679-2004. Agosto, 2005. Imprimir desde Java y .NET. [8] Sun begins releasing Java under the GPL - Free Software Foundation


4.3. JAVASCRIPT

4.2.13

67

Enlaces externos

Wikilibros •

Wikilibros alberga un libro o manual sobre Programación en Java.

• Programas hechos en java con código fuente • Recopilación de códigos fuente en java Oracle - Sun • Sitio oficial de Java para desarrolladores, etc • The Java Language Specification, Tercera edición Especificación oficial del lenguaje Java • Tutorial de Sun sobre el Lenguaje de programación Java • Libro blanco original de Java, 1996 Tutoriales • Thinking in Java, de Bruce Eckel (online) • An introduction to Computer Science using Java por Bradley Kjell. • Java Course, de A.B. Downey. • Computer-Books.us Colección de libros sobre Java disponibles para descarga gratuita. • En castellano: • VideoTutoriales para aprender desde cero «Empieza a Programar» • Colección «Java a tope» de libros electrónicos (Universidad de Málaga. España) • Curso de Java, de cero a hasta conexión a MYSQL, incluye PDF (México) • Curso de java que sigue el índice del libro de java de Kathy Sierra, contiene PDFs y ejercicios (México) • Capacitación en Java sobre Grandes Proyectos • Aprender programación Java desde cero (Portal web aprenderaprogramar.com, on-line y en formato pdf) • ¿Que es Java? (SoftMAS el blog para aprender a programar). Críticas • Softpanorama Java Critique Page: Java vs Scripting Languages, de Nikolai Bezroukov • How Java’s Floating-Point Hurts Everyone Everywhere, de W. Kahan und Joseph D. Darcy en el ACM 1998 Workshop on Java for High–Performance Network Computing

4.3 JavaScript JavaScript (abreviado comúnmente JS) es un lenguaje de programación interpretado, dialecto del estándar ECMAScript. Se define como orientado a objetos,[3] basado en prototipos, imperativo, débilmente tipado y dinámico. Se utiliza principalmente en su forma del lado del cliente (client-side), implementado como parte de un navegador web permitiendo mejoras en la interfaz de usuario y páginas web dinámicas[4] aunque existe una forma de JavaScript del lado del servidor (Server-side JavaScript o SSJS). Su uso en aplicaciones externas a la web, por ejemplo en documentos PDF, aplicaciones de escritorio (mayoritariamente widgets) es también significativo.


68

CAPÍTULO 4. TIPOS DE LENGUAJES

JavaScript se diseñó con una sintaxis similar al C, aunque adopta nombres y convenciones del lenguaje de programación Java. Sin embargo Java y JavaScript tienen semánticas y propósitos diferentes. Todos los navegadores modernos interpretan el código JavaScript integrado en las páginas web. Para interactuar con una página web se provee al lenguaje JavaScript de una implementación del Document Object Model (DOM). Tradicionalmente se venía utilizando en páginas web HTML para realizar operaciones y únicamente en el marco de la aplicación cliente, sin acceso a funciones del servidor. Actualmente es ampliamente utilizado para enviar y recibir información del servidor junto con ayuda de otras tecnologías como AJAX. JavaScript se interpreta en el agente de usuario al mismo tiempo que las sentencias van descargándose junto con el código HTML. Desde el lanzamiento en junio de 1997 del estándar ECMAScript 1, han existido las versiones 2, 3 y 5, que es la más usada actualmente (la 4 se abandonó[5] ). En junio de 2015 se cerró y publicó la versión ECMAScript 6[6] .

4.3.1

Historia

Nacimiento de JavaScript JavaScript fue desarrollado originalmente por Brendan Eich de Netscape con el nombre de Mocha, el cual fue renombrado posteriormente a LiveScript, para finalmente quedar como JavaScript. El cambio de nombre coincidió aproximadamente con el momento en que Netscape agregó compatibilidad con la tecnología Java en su navegador web Netscape Navigator en la versión 2.002 en diciembre de 1995. La denominación produjo confusión, dando la impresión de que el lenguaje es una prolongación de Java, y se ha caracterizado por muchos como una estrategia de mercadotecnia de Netscape para obtener prestigio e innovar en lo que eran los nuevos lenguajes de programación web.[7][8] «JAVASCRIPT» es una marca registrada de Oracle Corporation.[9] Es usada con licencia por los productos creados por Netscape Communications y entidades actuales como la Fundación Mozilla.[10][11] Microsoft dio como nombre a su dialecto de JavaScript «JScript», para evitar problemas relacionadas con la marca. JScript fue adoptado en la versión 3.0 de Internet Explorer, liberado en agosto de 1996, e incluyó compatibilidad con el Efecto 2000 con las funciones de fecha, una diferencia de los que se basaban en ese momento. Los dialectos pueden parecer tan similares que los términos «JavaScript» y «JScript» a menudo se utilizan indistintamente, pero la especificación de JScript es incompatible con la de ECMA en muchos aspectos. Para evitar estas incompatibilidades, el World Wide Web Consortium diseñó el estándar Document Object Model (DOM, o Modelo de Objetos del Documento en español), que incorporan Konqueror, las versiones 6 de Internet Explorer y Netscape Navigator, Opera la versión 7, Mozilla Application Suite y Mozilla Firefox desde su primera versión.[cita requerida] En 1997 los autores propusieron[12] JavaScript para que fuera adoptado como estándar de la European Computer Manufacturers 'Association ECMA, que a pesar de su nombre no es europeo sino internacional, con sede en Ginebra. En junio de 1997 fue adoptado como un estándar ECMA, con el nombre de ECMAScript. Poco después también como un estándar ISO. JavaScript en el lado servidor Netscape introdujo una implementación de script del lado del servidor con Netscape Enterprise Server, lanzada en diciembre de 1994 (poco después del lanzamiento de JavaScript para navegadores web).[13][14] A partir de mediados de la década de los 2000, ha habido una proliferación de implementaciones de JavaScript para el lado servidor. Node.js es uno de los notables ejemplos de JavaScript en el lado del servidor, siendo usado en proyectos importantes.[15][16] Desarrollos posteriores JavaScript se ha convertido en uno de los lenguajes de programación más populares en internet. Al principio, sin embargo, muchos desarrolladores renegaban del lenguaje porque el público al que va dirigido lo formaban publicadores de artículos y demás aficionados, entre otras razones.[17] La llegada de Ajax devolvió JavaScript a la fama y atrajo la atención de muchos otros programadores. Como resultado de esto hubo una proliferación de un conjunto de frameworks y librerías de ámbito general, mejorando las prácticas de programación con JavaScript, y aumentado el uso de JavaScript fuera de los navegadores web, como se ha visto con la proliferación de entornos JavaScript del lado


4.3. JAVASCRIPT

69

del servidor. En enero de 2009, el proyecto CommonJS fue inaugurado con el objetivo de especificar una librería para uso de tareas comunes principalmente para el desarrollo fuera del navegador web.[18] En junio de 2015 se cerró y publicó el estándar ECMAScript 6[19][20] (última versión hasta la fecha) con un soporte irregular entre navegadores[21] y que dota a JavaScript de características avanzadas que se echaban de menos y que son de uso habitual en otros lenguajes como, por ejemplo, módulos para organización del código, verdaderas clases para POO, expresiones de flecha, iteradores, generadores o promesas para programación asíncrona.

4.3.2

Características

Las siguientes características son comunes a todas las implementaciones que se ajustan al estándar ECMAScript, a menos que especifique explícitamente en caso contrario. Imperativo y estructurado JavaScript es compatible con gran parte de la estructura de programación de C (por ejemplo, sentencias if, bucles for, sentencias switch, etc.). Con una salvedad, en parte: en C, el ámbito de las variables alcanza al bloque en el cual fueron definidas; sin embargo JavaScript no es compatible con esto, puesto que el ámbito de las variables es el de la función en la cual fueron declaradas. Esto cambia con la versión de JavaScript 1.7, ya que añade compatibilidad con block scoping por medio de la palabra clave let. Como en C, JavaScript hace distinción entre expresiones y sentencias. Una diferencia sintáctica con respecto a C es la inserción automática de punto y coma, es decir, en JavaScript los puntos y coma que finalizan una sentencia pueden ser omitidos.[22] Dinámico Tipado dinámico Como en la mayoría de lenguajes de scripting, el tipo está asociado al valor, no a la variable. Por ejemplo, una variable x en un momento dado puede estar ligada a un número y más adelante, religada a una cadena. JavaScript es compatible con varias formas de comprobar el tipo de un objeto, incluyendo duck typing.[23] Una forma de saberlo es por medio de la palabra clave typeof. Objetual JavaScript está formado casi en su totalidad por objetos. Los objetos en JavaScript son arrays asociativos, mejorados con la inclusión de prototipos (ver más adelante). Los nombres de las propiedades de los objetos son claves de tipo cadena: obj.x = 10 y obj['x'] = 10 son equivalentes, siendo la notación con punto azúcar sintáctico. Las propiedades y sus valores pueden ser creados, cambiados o eliminados en tiempo de ejecución. La mayoría de propiedades de un objeto (y aquellas que son incluidas por la cadena de la herencia prototípica) pueden ser enumeradas a por medio de la instrucción de bucle for... in. JavaScript tiene un pequeño número de objetos predefinidos como son Function y Date. Evaluación en tiempo de ejecución JavaScript incluye la función eval que permite evaluar expresiones como expresadas como cadenas en tiempo de ejecución. Por ello se recomienda que eval sea utilizado con precaución y que se opte por utilizar la función JSON.parse() en la medida de lo posible, pues resulta mucho más segura. Funcional Funciones de primera clase A las funciones se les suele llamar ciudadanos de primera clase; son objetos en sí mismos. Como tal, poseen propiedades y métodos, como .call() y .bind().[24] Una función anidada es una función definida dentro de otra. Esta es creada cada vez que la función externa es invocada. Además, cada función creada forma una clausura; es el resultado de evaluar un ámbito conteniendo en una o más variables dependientes de otro ámbito externo, incluyendo constantes, variables locales y argumentos de la función externa llamante. El resultado de la evaluación de dicha clausura forma parte del estado interno de cada objeto función, incluso después de que la función exterior concluya su evaluación.[25] Prototípico Prototipos JavaScript usa prototipos en vez de clases para el uso de herencia.[26] Es posible llegar a emular muchas de las características que proporcionan las clases en lenguajes orientados a objetos tradicionales por medio de prototipos en JavaScript.[27]


70

CAPÍTULO 4. TIPOS DE LENGUAJES

Funciones como constructores de objetos Las funciones también se comportan como constructores. Prefijar una llamada a la función con la palabra clave new crear una nueva instancia de un prototipo, que heredan propiedades y métodos del constructor (incluidas las propiedades del prototipo de Object).[28] ECMAScript 5 ofrece el método Object.create, permitiendo la creación explícita de una instancia sin tener que heredar automáticamente del prototipo de Object (en entornos antiguos puede aparecer el prototipo del objeto creado como null).[29] La propiedad prototype del constructor determina el objeto usado para el prototipo interno de los nuevos objetos creados. Se pueden añadir nuevos métodos modificando el prototipo del objeto usado como constructor. Constructores predefinidos en JavaScript, como Array u Object, también tienen prototipos que pueden ser modificados. Aunque esto sea posible se considera una mala práctica modificar el prototipo de Object ya que la mayoría de los objetos en Javascript heredan los métodos y propiedades del objeto prototype, objetos los cuales pueden esperar que estos no hayan sido modificados.[30] Otras características Entorno de ejecución JavaScript normalmente depende del entorno en el que se ejecute (por ejemplo, en un navegador web) para ofrecer objetos y métodos por los que los scripts pueden interactuar con el “mundo exterior”. De hecho, depende del entorno para ser capaz de proporcionar la capacidad de incluir o importar scripts (por ejemplo, en HTML por medio del tag <script>). (Esto no es una característica del lenguaje, pero es común en la mayoría de las implementaciones de JavaScript.) Funciones variádicas Un número indefinido de parámetros pueden ser pasados a la función. La función puede acceder a ellos a través de los parámetros o también a través del objeto local arguments. Las funciones variádicas también pueden ser creadas usando el método .apply(). Funciones como métodos A diferencia de muchos lenguajes orientados a objetos, no hay distinción entre la definición de función y la definición de método. Más bien, la distinción se produce durante la llamada a la función; una función puede ser llamada como un método. Cuando una función es llamada como un método de un objeto, la palabra clave this, que es una variable local a la función, representa al objeto que invocó dicha función. Arrays y la definición literal de objetos Al igual que muchos lenguajes de script, arrays y objetos (arrays asociativos en otros idiomas) pueden ser creados con una sintaxis abreviada. De hecho, estos literales forman la base del formato de datos JSON. Expresiones regulares JavaScript también es compatible con expresiones regulares de una manera similar a Perl, que proporcionan una sintaxis concisa y poderosa para la manipulación de texto que es más sofisticado que las funciones incorporadas a los objetos de tipo string.[31] Extensiones específicas del fabricante JavaScript se encuentra oficialmente bajo la organización de Mozilla Foundation, y periódicamente se añaden nuevas características del lenguaje. Sin embargo, sólo algunos motores JavaScript son compatibles con estas características: • Las propiedades get y set (también compatibles con WebKit, Opera,[32] ActionScript y Rhino).[33] • Cláusulas catch condicionales. • Protocolo iterador adoptado de Python. • Corrutinas también adoptadas de Python. • Generación de listas y expresiones por comprensión también adoptado de Python. • Establecer el ámbito a bloque a través de la palabra clave let. • Desestructuración de arrays y objetos (forma limita de emparejamiento de patrones). • Expresiones concretas en funciones (function(args) expr). • ECMAScript para XML (E4X), una extensión que añade compatibilidad nativa XML a ECMAScript.


4.3. JAVASCRIPT

4.3.3

71

Sintaxis y semántica

A partir del 2011, la última versión del lenguaje es JavaScript 1.8.5. Es un superconjunto de la especificación ECMAScript (ECMA-262) Edición 3. Extensiones del lenguaje, que incluyen compatibilidad parcial con ECMAScript para XML (E4X) (ECMA-357) y características experimentales consideradas para ser incluidas en futuras ediciones del ECMAScript, documentadas aquí.[34] Ejemplos sencillos Las variables en JavaScript se definen usando la palabra clave var:[35] var x; // define la variable x, aunque no tiene ningún valor asignado por defecto var y = 2; // define la variable y y le asigna el valor 2 a ella A considerar los comentarios en el ejemplo de arriba, los cuales van precedidos con 2 barras diagonales. No existen funcionalidades para I/O incluidas en el lenguaje; el entorno de ejecución ya lo proporciona. La especificación ECMAScript en su edición 5.1 hace mención:[36] ... en efecto, no existen provisiones en esta especificación para entrada de datos externos o salida para resultados computados. Sin embargo, la mayoría de los entornos de ejecución tiene un objeto[37] llamado console que puede ser usado para imprimir por el flujo de salida de la consola de depuración. He aquí un simple programa que imprime “Hello world!”: console.log(“Hello world!"); Una función recursiva: function factorial(n) { if (n === 0) { return 1; } return n * factorial(n - 1); } Ejemplos de función anónima (o función lambda) y una clausura: var displayClosure = function() { var count = 0; return function () { return ++count; }; } var inc = displayClosure(); inc(); // devuelve 1 inc(); // devuelve 2 inc(); // devuelve 3 Las expresiones con invocación automática permiten a las funciones pasarle variables por parámetro dentro de sus propias clausuras. var v; v = 1; var getValue = (function(v) { return function() {return v;}; }(v)); v = 2; getValue(); // 1

Ejemplos más avanzados El siguiente código muestra varias características de JavaScript. /* Busca el mínimo común múltiplo (MCM) de dos números */ function LCMCalculator(x, y) { // función constructora var checkInt = function (x) { // función interior if (x % 1 !== 0) { throw new TypeError(x + " no es un entero”); // lanza una excepción } return x; }; this.a = checkInt(x) // puntos y coma son opcionales this.b = checkInt(y); } // El prototipo de las instancias de objeto creados por el constructor es el de la propiedad “prototype” del constructor. LCMCalculator.prototype = { // objeto definido como literal constructor: LCMCalculator, // cuando reasignamos un prototipo, establecemos correctamente su propiedad constructor gcd: function () { // método que calcula el máximo común divisor // Algoritmo de Euclides: var a = Math.abs(this.a), b = Math.abs(this.b), t; if (a < b) { // intercambiamos variables t = b; b = a; a = t; } while (b !== 0) { t = b; b = a % b; a = t; } // Solo necesitamos calcular el MCD una vez, por lo tanto 'redefinimos’ este método. // (Realmente no es una redefinición—está definida en la propia instancia, por lo tanto // this.gcd se refiere a esta 'redefinición' en vez de a LCMCalculator.prototype.gcd). // Además, 'gcd' === “gcd”, this['gcd'] === this.gcd this['gcd'] = function () { return a; }; return a; }, // Los nombres de las propiedades del objeto pueden ser especificados con cadenas delimitadas con comillas simples (') o dobles (“). “lcm” : function () { // Los nombres de las variables no colisionan con las propiedades del objeto. Por ejemplo: |lcm| no es |this.lcm|. // No usar |this.a * this.b| para evitar problemas con cálculos en coma flotante. var lcm


72

CAPÍTULO 4. TIPOS DE LENGUAJES

= this.a / this.gcd() * this.b; // Sólo necesitamos calcular MCM una vez, por lo tanto “redefinimos” este método. this.lcm = function () { return lcm; }; return lcm; }, toString: function () { return “LCMCalculator: a = " + this.a + ", b = " + this.b; } }; // Definimos una función genérica para imprimir un resultado; esta implementación solo funciona en los navegadores web function output(x) { document.body.appendChild(document.createTextNode(x)); document.body.appendChild(document.createElement('br')); } // Nota: Los métodos.map() y.forEach() del prototipo Array están definidos en JavaScript 1.6. // Estos métodos son usados aquí para demostrar la naturaleza funcional inherente del lenguaje. [[25, 55], [21, 56], [22, 58], [28, 56]].map(function (pair) { // contrucción literal de un Array + función de mapeo. return new LCMCalculator(pair[0], pair[1]); }).sort(function (a, b) { // ordenamos la colección por medio de esta función return a.lcm() - b.lcm(); }).forEach(function (obj) { output(obj + ", gcd = " + obj.gcd() + ", lcm = " + obj.lcm()); }); El siguiente ejemplo muestra la salida que debería ser mostrada en la ventana de un navegador. LCMCalculator: a = 28, b = 56, gcd = 28, lcm = 56 LCMCalculator: a = 21, b = 56, gcd = 7, lcm = 168 LCMCalculator: a = 25, b = 55, gcd = 5, lcm = 275 LCMCalculator: a = 22, b = 58, gcd = 2, lcm = 638

4.3.4

Uso en páginas web

El uso más común de JavaScript es escribir funciones embebidas o incluidas en páginas HTML y que interactúan con el Document Object Model (DOM o Modelo de Objetos del Documento) de la página. Algunos ejemplos sencillos de este uso son: • Cargar nuevo contenido para la página o enviar datos al servidor a través de AJAX sin necesidad de recargar la página (por ejemplo, una red social puede permitir al usuario enviar actualizaciones de estado sin salir de la página). • Animación de los elementos de página, hacerlos desaparecer, cambiar su tamaño, moverlos, etc. • Contenido interactivo, por ejemplo, juegos y reproducción de audio y vídeo. • Validación de los valores de entrada de un formulario web para asegurarse de que son aceptables antes de ser enviado al servidor. • Transmisión de información sobre los hábitos de lectura de los usuarios y las actividades de navegación a varios sitios web. Las páginas Web con frecuencia lo hacen para hacer análisis web, seguimiento de anuncios, la personalización o para otros fines.[38] Dado que el código JavaScript puede ejecutarse localmente en el navegador del usuario (en lugar de en un servidor remoto), el navegador puede responder a las acciones del usuario con rapidez, haciendo una aplicación más sensible. Por otra parte, el código JavaScript puede detectar acciones de los usuarios que HTML por sí sola no puede, como pulsaciones de teclado. Las aplicaciones como Gmail se aprovechan de esto: la mayor parte de la lógica de la interfaz de usuario está escrita en JavaScript, enviando peticiones al servidor (por ejemplo, el contenido de un mensaje de correo electrónico). La tendencia cada vez mayor por el uso de la programación Ajax explota de manera similar esta técnica. Un motor de JavaScript (también conocido como intérprete de JavaScript o implementación JavaScript) es un intérprete que interpreta el código fuente de JavaScript y ejecuta la secuencia de comandos en consecuencia. El primer motor de JavaScript fue creado por Brendan Eich en Netscape Communications Corporation, para el navegador web Netscape Navigator. El motor, denominado SpiderMonkey, está implementado en C. Desde entonces, ha sido actualizado (en JavaScript 1.5) para cumplir con el ECMA-262 edición 3. El motor Rhino, creado principalmente por Norris Boyd (antes de Netscape, ahora en Google) es una implementación de JavaScript en Java. Rhino, como SpiderMonkey, es compatible con el ECMA-262 edición 3. Un navegador web es, con mucho, el entorno de acogida más común para JavaScript. Los navegadores web suelen crear objetos no nativos, dependientes del entorno de ejecución, para representar el Document Object Model (DOM) en JavaScript. El servidor web es otro entorno común de servicios. Un servidor web JavaScript suele exponer sus propios objetos para representar objetos de petición y respuesta HTTP, que un programa JavaScript podría entonces interrogar y manipular para generar dinámicamente páginas web.


4.3. JAVASCRIPT

73

Debido a que JavaScript es el único lenguaje por el que los más populares navegadores comparten su apoyo, se ha convertido en un lenguaje al que muchos frameworks en otros lenguajes compilan, a pesar de que JavaScript no fue diseñado para tales propósitos.[39] A pesar de las limitaciones de rendimiento inherentes a su naturaleza dinámica, el aumento de la velocidad de los motores de JavaScript ha hecho de este lenguaje un entorno para la compilación sorprendentemente factible. Ejemplo de script A continuación se muestra un breve ejemplo de una página web (ajustadose a las normas del estándar para HTML5) que utiliza JavaScript para el manejo del DOM: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Ejemplo sencillo</title> <h1 id="header">Esto es JavaScript</h1> <script> document.body.appendChild(document.createTextNode('Hola Mundo!')); var h1 = document.getElementById('header'); // contiene la referencia al tag <h1> h1 = document.getElementsByTagName('h1')[0]; // accediendo al mismo elemento <h1> </script> <noscript>Tu navegador no admite JavaScript, o JavaScript está deshabilitado.</noscript> </head> <body>/*...*/</body> </html>

Consideraciones acerca de la compatibilidad Debido a que JavaScript se ejecuta en entornos muy variados, una parte importante de las pruebas y la depuración es probar y verificar que el código JavaScript funciona correctamente en múltiples navegadores. La interfaz DOM para acceder y manipular páginas web no es parte del estándar ECMAScript, o de la propia JavaScript. El DOM es definido por los esfuerzos de estandarización del W3C, una organización independiente. En la práctica, las implementaciones que hacen de JavaScript los distintos navegadores difieren tanto entre ellos mismos como de las normas del estándar. Para hacer frente a estas diferencias, los autores de JavaScript pudieron ser capaces de escribir código compatible con los estándares que también fuera capaz de ejecutarse correctamente en la mayoría de los navegadores, o en su defecto, que al menos se pudiera escribir código capaz de comprobar la presencia de ciertas funcionalidades del navegador y que se comportase de manera diferente si no se dispusiese de dicha funcionalidad.[40] Existen casos en los que dos navegadores pueden llegar a implementar la misma característica, pero con un comportamiento diferente, hecho que a los programadores les puede resultar de ayuda para detectar qué navegador se está ejecutando en ese instante y así cambiar el comportamiento de su escritura para que coincida.[41][42] Los programadores también suelen utilizar bibliotecas o herramientas que tengan en cuenta las diferencias entre navegadores. Además, los scripts pueden no funcionar para algunos usuarios. Por ejemplo, un usuario puede: • utilizar un navegador antiguo sin compatibilidad completa con la API DOM, • utilizar un navegador PDA o teléfono móvil que no puede ejecutar JavaScript • tener la ejecución de JavaScript deshabilitada, como precaución de seguridad, • utilizar un navegador de voz debido a, por ejemplo, una discapacidad visual. Para apoyar a estos usuarios, los programadores web suelen crear páginas que sean tolerante a fallos según el agente de usuario (tipo de navegador) que no admita JavaScript. En particular, la página debe seguir siendo útil aunque sin las características adicionales que JavaScript habría añadido. Un enfoque alternativo que muchos encuentran preferible es primero crear contenido utilizando las tecnologías que funcionan en todos los navegadores, y mejorar el contenido para los usuarios que han permitido JavaScript. Accesibilidad Suponiendo que el usuario no haya desactivado la ejecución de código JavaScript, en el lado del cliente JavaScript debe ser escrito tanto con el propósito de mejorar las experiencias de los visitantes con discapacidad visual o física, como el de evitar ocultar información a estos visitantes.[43] Los lectores de pantalla, utilizados por los ciegos y deficientes visuales, pueden ser tenidos en cuenta por JavaScript y así poder acceder y leer los elementos DOM de la página. El código HTML escrito debe ser lo más conciso, navegable y semánticamente rico posible, tanto si JavaScript se ejecuta como si no.


74

CAPÍTULO 4. TIPOS DE LENGUAJES

JavaScript no debería de ser totalmente dependiente de los eventos de ratón del navegador y debería ser accesible para aquellos usuarios que no quieran hacer uso del ratón (informática) para navegar o que opten por utilizar solamente el teclado. Hay eventos independientes del dispositivo, tales como onfocus y onchange que son preferibles en la mayoría de los casos.[43] JavaScript no debe ser utilizado para crear confusión o desorientación al usuario web. Por ejemplo, modificar o desactivar la funcionalidad normal del navegador, como cambiar la forma en que el botón de navegar hacia atrás o el evento de actualización se comportan, son prácticas que generalmente son mejores evitar. Igualmente, desencadenar eventos que el usuario puede no tener en cuenta reduce la sensación de control del usuario y provoca cambios inesperados al contenido de la página.[44] A menudo, el proceso de dotar a una página web compleja el mayor grado accesibilidad posible, se convierte en un problema no trivial donde muchos temas se acaban llevando al debate y a la opinión, siendo necesario el compromiso de todos hasta el final. Sin embargo, los agentes de usuario y las tecnologías de apoyo a personas con discapacidad están en constante evolución y nuevas directrices e información al respecto siguen publicándose en la web.[43]

4.3.5

Seguridad

JavaScript y el DOM permite que existan programadores que hagan un uso inapropiado para introducir scripts que ejecuten código con contenido malicioso sin el consentimiento del usuario y que pueda así comprometer su seguridad. Los desarrolladores de los navegadores tienen en cuenta este riesgo utilizando dos restricciones. En primer lugar, los scripts se ejecutan en un sandbox en el que sólo se pueden llevar a cabo acciones relacionadas con la web, no con tareas de programación de propósito general, como la creación de archivos. En segundo lugar, está limitada por la política del mismo origen: los scripts de un sitio web no tienen acceso a la información enviada a otro sitio web (de otro dominio) como pudiera ser nombres de usuario, contraseñas o cookies. La mayoría de los fallos de seguridad de JavaScript están relacionados con violaciones de cualquiera de estas dos restricciones. Existen proyectos como AdSafe o Secure ECMA script (SES) que proporcionan mayores niveles de seguridad, en especial en el código creado por terceros (tales como los anuncios).[45][46] La Política de Contenido Seguro (CSP) es el método principal previsto para garantizar que sólo código de confianza pueda ser ejecutado en una página web. Vulnerabilidades cross-site Un problema común de seguridad en JavaScript es el cross-site scripting o XSS, una violación de la política de mismo origen. Las vulnerabilidades XSS permiten a un atacante inyectar código JavaScript en páginas web visitadas por el usuario. Una de esas webs podría ser la de un banco, pudiendo el atacante acceder a la aplicación de banca con los privilegios de la víctima, lo que podría revelar información secreta o transferir dinero sin la autorización de la víctima. Una solución para las vulnerabilidades XSS es utilizar HTML escapar cuando la visualización de datos no confiables. Algunos navegadores incluyen una protección parcial contra los ataques XSS reflejados (el atacante está en la misma petición web). El atacante proporciona una URL incluyendo código malicioso. Sin embargo, incluso los usuarios de los navegadores son vulnerables a otros ataques XSS, tales como aquellos en los que el código malicioso se almacena en una base de datos. Sólo el correcto diseño de las aplicaciones Web en la parte servidora puede prevenir totalmente XSS. Las vulnerabilidades XSS también pueden ocurrir debido a errores de ejecución por los desarrolladores del navegador.[47] Otra vulnerabilidad es la falsificación de petición de sitio cruzado o CSRF. En CSRF, el código del sitio web atacante engaña al navegador de la víctima, permitiendo al atacante realizar peticiones en nombre de la víctima, haciendo imposible saber a la aplicación de destino (por ejemplo, la de un banco haciendo una transferencia de dinero) saber si la petición ha sido realizada voluntariamente por el usuario o por un ataque CSRF. El ataque funciona porque, si el sitio de destino hace uso únicamente de las cookies para autenticar las solicitudes de la víctima, las peticiones iniciadas por el código del atacante tendrán las mismas credenciales de acceso legítimo que las solicitudes iniciadas por el propio usuario. En general, la solución a CSRF consiste en introducir un campo de formulario oculto cuyo valor se utilice para realizar la autenticación, y no sólo por medio de las cookies, en solicitudes que puedan tener efectos duraderos. La comprobación de la cabecera HTTP referer también puede servir de ayuda. “Hijacking JavaScript” es un tipo de ataque CSRF en el que una etiqueta <script> en el sitio web del atacante explota


4.3. JAVASCRIPT

75

una vulnerabilidad en la página del sitio de la víctima que le hace devolver información privada, en forma de JSON o código JavaScript. Las posibles soluciones son: • que se requiera un token de autenticación en los parámetros de las peticiones POST y GET para aquellas peticiones que requieran devolver información privada del usuario. • usar POST y nunca GET para solicitudes que devuelven información privada

4.3.6

Herramientas de desarrollo

En JavaScript, disponer de un depurador se convierte en necesario cuando se desarrollan grandes aplicaciones, no triviales. Dado que puede haber diferencias de implementación entre los diferentes navegadores (especialmente en cuanto al DOM), es útil tener acceso a un depurador para cada uno de los navegadores a los cuales nuestra aplicación web irá dirigido.[48] Los depuradores web están disponibles para Internet Explorer, Firefox, Safari, Google Chrome y Opera.[49] Existen tres depuradores disponibles para Internet Explorer: Microsoft Visual Studio es el más avanzado de los tres, seguido de cerca por Microsoft Script Editor (un componente de Microsoft Office)[50] y, finalmente, Microsoft Script Debugger, que es mucho más básico que el otro dos, aunque es gratuito. El IDE gratuito Microsoft Visual Web Developer Express ofrece una versión limitada de la funcionalidad de depuración de JavaScript en el Microsoft Visual Studio. Internet Explorer ha incluido herramientas de desarrollo desde la versión 8 (se muestra pulsando la tecla F12). Las aplicaciones web dentro de Firefox se pueden depurar usando el Firebug add-on o el antiguo depurador Venkman. Firefox también tiene integrada una consola de errores básica, que registra y evalúa JavaScript. También registra errores de CSS y advertencias. Opera incluye un conjunto de herramientas llamado Dragonfly.[51] El Inspector Web de WebKit incluye un depurador de JavaScript[52] utilizado en Safari, junto con una versión modificada de Google Chrome. Existen algunas herramientas de ayuda a la depuración, también escritas en JavaScript y construidas para ejecutarse en la Web. Un ejemplo es el programa JSLint, desarrollado por Douglas Crockford, quien ha escrito extensamente sobre el lenguaje. JSLint analiza el código JavaScript para que este quede conforme con un conjunto de normas y directrices y que aseguran su correcto funcionamiento y mantenibilidad.

4.3.7

Referencias

[1] Douglas Crockford on Functional JavaScript (2:49): "[JavaScript] es el lenguaje funcional más popular del mundo. JavaScript es y siempre ha sido, al menos desde [la versión] 1.2, un lenguaje de programación funcional.” [2] RFC 4329 [3] http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf [4] M. Domínguez-Dorado,. Todo Programación. Nº 12. Págs. 48-51. Editorial Iberprensa(Madrid). DL M-13679-2004. Septiembre de 2005. Bases de datos en el cliente con JavaScript DB. [5] Eich, Brendan (13 de agosto de 2008). «ECMAScript Harmony». Consultado el 22 de julio de 2015. [6] campusMVP (19 de junio de 2015). «ECMAScript 6 es ya un estándar cerrado». Consultado el 22 de julio de 2015. [7] Lenguajes de programación usados en Internet y la World Wide Web (WWW) (castellano) [8] .com/0596101996/jscript5-CHP-1 O'Reilly - Safari Books Online - 0596101996 - JavaScript: The Definitive Guide, 5 ª edición (castellano) [9] http://tsdr.uspto.gov/#caseNumber=75026640&caseType=SERIAL_NO&searchType=statusSearch [10] Marcas registradas de Oracle. [11] «About JavaScript» (en inglés). Consultado el 29 de agosto de 2013. «JavaScript is a trademark or registered trademark of Oracle in the U.S. and other countries». [12] Netscape Comunicado de prensa (castellano) [13] «Chapter 2: Getting Started». Server-Side JavaScript Guide. Netscape Communications Corporation. 1998. Consultado el 25 de abril de 2012.


76

CAPÍTULO 4. TIPOS DE LENGUAJES

[14] Mike Morgan (1996). «Chapter 6: Netscape Internet Application Framework». Using Netscape™ LiveWire™, Special Edition. Que. Archivado desde el original el 27 de noviembre de 2015. [15] «Server-Side Javascript: Back With a Vengeance». Read Write Web. 17 de diciembre de 2009. Consultado el 28 de mayo de 2012. [16] «Node’s goal is to provide an easy way to build scalable network programs». About Node.js. Joyent. [17] «JavaScript: The World’s Most Misunderstood Programming Language». Crockford.com. Consultado el 19 de mayo de 2009. [18] Kris Kowal (1 de diciembre de 2009). «CommonJS effort sets JavaScript on path for world domination». Ars Technica. Condé Nast Publications. Consultado el 18 de abril de 2010. [19] ECMA International (Junio de 2015). «Standard ECMA-262 6th Edition». [20] campusMVP (19 de junio de 2015). «ECMAScript 6 ya es un estándar cerrado». Consultado el 22 de julio de 2015. [21] «Tabla de compatibilidadde navegadores con ECMAScript 6 (Inglés)». [22] Flanagan, 2006, p. 16. [23] Flanagan, 2006, pp. 176–178. [24] Properties of the Function Object [25] Flanagan, 2006, p. 141. [26] «Inheritance and the prototype chain». Mozilla Developer Network. Mozilla. Consultado el 6 de abril de 2013. [27] Herman, David (2013). Effective Javascript. Addison-Wesley. p. 83. ISBN 9780321812186. [28] Haverbeke, Marjin (2011). Eloquent Javascript. No Starch Press. pp. 95-97. ISBN 9781593272821. [29] Katz, Yehuda. «Understanding “Prototypes” in JavaScript». Consultado el 6 de abril de 2013. [30] Herman, David (2013). Effective Javascript. Addison-Wesley. pp. 125-127. ISBN 9780321812186. [31] Haverbeke, Marijn (2011). Eloquent JavaScript. No Starch Press. pp. 139-149. ISBN 978-1593272821. [32] Robert Nyman, Getters And Setters With JavaScript – Code Samples And Demos, published 29 May 2009, accessed 2 January 2010. [33] John Resig, JavaScript Getters and Setters, 18 July 2007, accessed 2 January 2010 [34] «MDN - About this Reference». Developer.mozilla.org. 31 de agosto de 2008. Consultado el 19 de mayo de 2009. [35] «var - JavaScript - MDN». The Mozilla Developer Network. Consultado el 22 de diciembre de 2012. [36] «ECMAScript Language Specification - ECMA-262 Edition 5.1». Ecma International. Consultado el 22 de diciembre de 2012. [37] «console». Mozilla Developer Network. Mozilla. Consultado el 6 de abril de 2013. [38] «JavaScript tracking - Piwik». Piwik. Consultado el 31 de marzo de 2012. [39] Hamilton, Naomi (31 de junio de 2008). «The A-Z of Programming Languages: JavaScript». computerworld.com.au. [40] Peter-Paul Koch, Object detection [41] Peter-Paul Koch, Mission Impossible - mouse position [42] Peter-Paul Koch, Browser detect [43] Flanagan, 2006, pp. 262–263. [44] «Creating Accessible JavaScript». WebAIM. Consultado el 8 de junio de 2010. [45] ADsafe - Making JavaScript Safe for Advertising [46] Secure ECMA Script (SES) [47] MozillaZine, Mozilla Cross-Site Scripting Vulnerability Reported and Fixed


4.4. PHP

77

[48] «Advanced Debugging With JavaScript». alistapart.com. 3 de febrero de 2009. Consultado el 28 de mayo de 2010. [49] «The JavaScript Debugging Console». javascript.about.com. 28 de mayo de 2010. Consultado el 28 de mayo de 2010. [50] JScript development in Microsoft Office 11 (MS InfoPath 2003) [51] «Opera DragonFly». Opera Software. [52] «Introducing Drosera - Surfin' Safari». Webkit.org. 28 de junio de 2006. Consultado el 19 de mayo de 2009.

4.3.8

Véase también

• VBScript • AJAX • Aplicación web • Document Object Model • JSON • HTML

4.3.9

Bibliografía

• Flanagan, David; Ferguson, Paula (2002). JavaScript: The Definitive Guide (4.ª edición). ISBN 0-596-00048-0.

4.3.10

Enlaces externos

• Mozilla Developer Center • slice( ) - O'Reilly Answers (en inglés) • Distinción entre variables locales y globales • Javascript tutorial

4.4 PHP PHP es un lenguaje de programación de uso general de código del lado del servidor originalmente diseñado para el desarrollo web de contenido dinámico. Fue uno de los primeros lenguajes de programación del lado del servidor que se podían incorporar directamente en el documento HTML en lugar de llamar a un archivo externo que procese los datos. El código es interpretado por un servidor web con un módulo de procesador de PHP que genera la página web resultante. PHP ha evolucionado por lo que ahora incluye también una interfaz de línea de comandos que puede ser usada en aplicaciones gráficas independientes. Puede ser usado en la mayoría de los servidores web al igual que en casi todos los sistemas operativos y plataformas sin ningún costo. PHP se considera uno de los lenguajes más flexibles, potentes y de alto rendimiento conocidos hasta el día de hoy[cita requerida] , lo que ha atraído el interés de múltiples sitios con gran demanda de tráfico, como Facebook, para optar por el mismo como tecnología de servidor. Fue creado originalmente por Rasmus Lerdorf en 1995. Actualmente el lenguaje sigue siendo desarrollado con nuevas funciones por el grupo PHP.[1] Este lenguaje forma parte del software libre publicado bajo la licencia PHP, que es incompatible con la Licencia Pública General de GNU debido a las restricciones del uso del término PHP.[2]


78

4.4.1

CAPÍTULO 4. TIPOS DE LENGUAJES

Etimología

PHP es un acrónimo recursivo que significa PHP Hypertext Pre-processor (inicialmente PHP Tools, o, Personal Home Page Tools).[3] Fue creado originalmente por Rasmus Lerdorf; sin embargo la implementación principal de PHP es producida ahora por The PHP Group y sirve como el estándar de facto para PHP al no haber una especificación formal. Publicado bajo la PHP License, la Free Software Foundation considera esta licencia como software libre.[2]

4.4.2

Visión general

PHP puede ser desplegado en la mayoría de los servidores web y en casi todos los sistemas operativos y plataformas sin costo alguno. El lenguaje PHP se encuentra instalado en más de 20 millones de sitios web y en un millón de servidores. El enorme número de sitios en PHP ha visto reducida su cantidad a favor de otros nuevos lenguajes no tan poderosos desde agosto de 2005. El sitio web de Wikipedia está desarrollado en PHP.[4] Es también el módulo Apache más popular entre las computadoras que utilizan Apache como servidor web. El gran parecido que posee PHP con los lenguajes más comunes de programación estructurada, como C y Perl, permiten a la mayoría de los programadores crear aplicaciones complejas con una curva de aprendizaje muy corta. También les permite involucrarse con aplicaciones de contenido dinámico sin tener que aprender todo un nuevo grupo de funciones. Aunque todo en su diseño está orientado a facilitar la creación de sitios webs, es posible crear aplicaciones con una interfaz gráfica para el usuario, utilizando alguna extensión como puede ser PHP-Qt, PHP-GTK,[5] WxPHP, WinBinder, Roadsend PHP, Phalanger, Phc o HiP Hop VM. También puede ser usado desde la línea de comandos, de la misma manera como Perl o Python pueden hacerlo; a esta versión de PHP se la llama PHP-CLI (Command Line Interface).[6] Cuando el cliente hace una petición al servidor para que le envíe una página web, el servidor ejecuta el intérprete de PHP. Éste procesa el script solicitado que generará el contenido de manera dinámica (por ejemplo obteniendo información de una base de datos). El resultado es enviado por el intérprete al servidor, quien a su vez se lo envía al cliente. Mediante extensiones es también posible la generación de archivos PDF,[7] Flash, así como imágenes en diferentes formatos. Permite la conexión a diferentes tipos de servidores de bases de datos tanto SQL como NoSQL tales como MySQL, PostgreSQL, Oracle, ODBC, DB2, Microsoft SQL Server, Firebird, SQLite o MongoDB.[8] PHP también tiene la capacidad de ser ejecutado en la mayoría de los sistemas operativos, tales como Unix (y de ese tipo, como Linux o Mac OS X) y Microsoft Windows, y puede interactuar con los servidores de web más populares ya que existe en versión CGI, módulo para Apache, e ISAPI. PHP es una alternativa a las tecnologías de Microsoft ASP y ASP.NET (que utiliza C# y Visual Basic .NET como lenguajes), a ColdFusion de la empresa Adobe, a JSP/Java, CGI/Perl y a Node.js/Javascript. Aunque su creación y desarrollo se da en el ámbito de los sistemas libres, bajo la licencia GNU, existe además un entorno de desarrollo integrado comercial llamado Zend Studio. CodeGear (la división de lenguajes de programación de Borland) ha sacado al mercado un entorno de desarrollo integrado para PHP, denominado 'Delphi for PHP. También existen al menos un par de módulos para Eclipse, uno de los entornos más populares.[9]

4.4.3

Historia

Fue originalmente diseñado en Perl, con base en la escritura de un grupo de CGI binarios escritos en el lenguaje C por el programador danés-canadiense Rasmus Lerdorf en el año 1994 para mostrar su currículum vítae y guardar ciertos datos, como la cantidad de tráfico que su página web recibía. El 8 de junio de 1995 fue publicado “Personal Home Page Tools” después de que Lerdorf lo combinara con su propio Form Interpreter para crear PHP/FI. Dos programadores israelíes del Technion, Zeev Suraski y Andi Gutmans, reescribieron el analizador sintáctico (parser en inglés) en el año 1997 y crearon la base del PHP3, cambiando el nombre del lenguaje por PHP: Hypertext Preprocessor.[1] Inmediatamente comenzaron experimentaciones públicas de PHP3 y fue publicado oficialmente en junio de 1998. Para 1999, Suraski y Gutmans reescribieron el código de PHP, produciendo lo que hoy se conoce como motor Zend. También fundaron Zend Technologies en Ramat Gan, Israel.[1] En mayo de 2000 PHP 4 fue lanzado bajo el poder del motor Zend 1.0. El día 13 de julio de 2007 se anunció la


4.4. PHP

79

suspensión del soporte y desarrollo de la versión 4 de PHP,[10] a pesar de lo anunciado se ha liberado una nueva versión con mejoras de seguridad, la 4.4.8 publicada el 13 de enero de 2008 y posteriormente la versión 4.4.9 publicada el 7 de agosto de 2008.[11] Según esta noticia[12] se le dio soporte a fallos críticos hasta el 9 de agosto de 2008. El 13 de julio de 2004, fue lanzado PHP 5, utilizando el motor Zend Engine 2.0 (o Zend Engine 2).[1] Incluye todas las ventajas que provee el nuevo Zend Engine 2 como: • Mejor soporte para la programación orientada a objetos, que en versiones anteriores era extremadamente rudimentario. • Mejoras de rendimiento. • Mejor soporte para MySQL con extensión completamente reescrita. • Mejor soporte a XML (XPath, DOM, etc.). • Soporte nativo para SQLite. • Soporte integrado para SOAP. • Iteradores de datos. • Manejo de excepciones. • Mejoras con la implementación con Oracle. Historial de lanzamiento

4.4.4

Sintaxis

Programa Hola mundo con PHP embebido en código HTML: <!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8” /> <title> Ejemplo básico PHP</title> </head> <body> <?php echo 'Hola mundo'; ?> </body> </html> El intérprete de PHP solo ejecuta el código que se encuentra entre sus delimitadores. Los delimitadores más comunes son <?php para abrir una sección PHP y ?> para cerrarla. El propósito de estos delimitadores es separar el código PHP del resto de código, como por ejemplo el HTML.[26] Las variables se prefijan con el símbolo del dólar ($) y no es necesario indicar su tipo. Las variables, a diferencia de las funciones, distinguen entre mayúsculas y minúsculas. Las cadenas de caracteres pueden ser encapsuladas tanto en dobles comillas como en comillas simples, aunque en el caso de las primeras, se pueden insertar variables en la cadena directamente, sin necesidad de concatenación. Los comentarios se pueden escribir bien con dos barras al principio de la línea, o con una almohadilla. También permite comentarios multi-línea encapsulados en /* */. En cuanto a las palabras clave, PHP comparte con la mayoría de otros lenguajes con sintaxis C las condiciones con if, los bucles con for y while y los retornos de funciones. Como es habitual en este tipo de lenguajes, las sentencias deben acabar con punto y coma (;).

4.4.5

Características de PHP

Características • Orientado al desarrollo de aplicaciones web dinámicas con acceso a información almacenada en una base de datos. • Es considerado un lenguaje fácil de aprender, ya que en su desarrollo se simplificaron distintas especificaciones, como es el caso de la definición de las variables primitivas, ejemplo que se hace evidente en el uso de php arrays. • El código fuente escrito en PHP es invisible al navegador web y al cliente, ya que es el servidor el que se encarga de ejecutar el código y enviar su resultado HTML al navegador.


80

CAPÍTULO 4. TIPOS DE LENGUAJES • Capacidad de conexión con la mayoría de los motores de base de datos que se utilizan en la actualidad, destaca su conectividad con MySQL y PostgreSQL. • Capacidad de expandir su potencial utilizando módulos (llamados ext’s o extensiones). • Posee una amplia documentación en su sitio web oficial, entre la cual se destaca que todas las funciones del sistema están explicadas y ejemplificadas en un único archivo de ayuda. • Es libre, por lo que se presenta como una alternativa de fácil acceso para todos. • Permite aplicar técnicas de programación orientada a objetos. • No requiere definición de tipos de variables aunque sus variables se pueden evaluar también por el tipo que estén manejando en tiempo de ejecución. • Tiene manejo de excepciones (desde PHP5). • Si bien PHP no obliga a quien lo usa a seguir una determinada metodología a la hora de programar, aún haciéndolo, el programador puede aplicar en su trabajo cualquier técnica de programación o de desarrollo que le permita escribir código ordenado, estructurado y manejable. Un ejemplo de esto son los desarrollos que en PHP se han hecho del patrón de diseño Modelo Vista Controlador (MVC), que permiten separar el tratamiento y acceso a los datos, la lógica de control y la interfaz de usuario en tres componentes independientes. • Debido a su flexibilidad ha tenido una gran acogida como lenguaje base para las aplicaciones WEB de manejo de contenido, y es su uso principal.

Inconvenientes • Como es un lenguaje que se interpreta en ejecución, para ciertos usos puede resultar un inconveniente que el código fuente no pueda ser ocultado. La ofuscación es una técnica que puede dificultar la lectura del código pero no necesariamente impide que el código sea examinado. • Debido a que es un lenguaje interpretado, un script en PHP suele funcionar considerablemente más lento que su equivalente en un lenguaje de bajo nivel, sin embargo este inconveniente se puede minimizar con técnicas de caché tanto en archivos como en memoria. • En las versiones previas a la 7, las variables no son tipificadas, lo cual dificulta a los diferentes IDEs ofrecer asistencias para el tipificado del código, aunque esto no es realmente un inconveniente del lenguaje en sí. Esto es solventado por algunos IDEs añadiendo un comentario con el tipo a la declaración de la variable.

XAMPP, LAMP, WAMP, MAMP, UwAmp XAMPP es un servidor independiente de plataforma, software libre, que consiste principalmente en la base de datos MySQL, el servidor Web Apache y los intérpretes para lenguajes de script: PHP y Perl. El nombre proviene del acrónimo de X (para cualquiera de los diferentes sistemas operativos), Apache, MySQL, PHP, Perl. El programa está liberado bajo la licencia GNU y actúa como un servidor Web libre, fácil de usar y capaz de interpretar páginas dinámicas. Actualmente XAMPP esta disponible para Microsoft Windows, GNU/Linux, Solaris, y MacOS X. Es un software “liviano” que se puede utilizar en cualquier PC. No necesita muchos recursos. LAMP presenta una funcionalidad parecida a XAMPP, pero enfocada en Linux, WAMP lo hace enfocado en Windows, y MAMP para MacOS X. UwAmp es muy idéntico a WAMP y se destaca en que se puede ejecutar desde una memoria USB.

Principales sitios desarrollados con PHP Se utiliza PHP en millones de sitios; entre los más destacados se encuentran Wikipedia.org, Facebook.com y Wordpress.com.


4.4. PHP

4.4.6

81

Referencias

[1] «Historia de PHP y Proyectos Relacionados». Archivado desde el original el 30 de noviembre de 2015. Consultado el 17 de octubre de 2012. [2] «Proyecto GNU - Licencias de software libre incompatibles con la GPL». Consultado el 17 de octubre de 2012. [3] FAQ General PHP.net. [4] «Historical trends in the usage of server-side programming languages for websites» (en inglés). W3Techs. Consultado el 10 de septiembre de 2013. [5] «PHP-GTK» (en inglés). PHP Group. Consultado el 10 de septiembre de 2013. [6] «PHP: Funcionamiento en línea de comandos». PHP Group. Consultado el 10 de septiembre de 2013. [7] «dompdf - HTML to PDF converter (PHP5)» (en inglés). Consultado el 10 de septiembre de 2013. [8] «PHP: Extensiones de bases de datos - Manual». PHP Group. Consultado el 10 de septiembre de 2013. [9] Existen tanto PHPEclipse como PDT for Eclipse. Véanse http://www.phpeclipse.com y http://www.eclipse.org/pdt [10] PHP: News Archives 2007 (en inglés). Consultado 9 de diciembre de 2007. [11] PHP: News Archives 2008 (en inglés). [12] Archivo: 13 de julio de 2007 PHP.net. [13] «History of PHP and related projects». The PHP Group. Consultado el 25 de febrero de 2008. [14] «PHP: PHP 4 ChangeLog». The PHP Group. 3 de enero de 2008. Consultado el 22 de febrero de 2008. [15] «PHP: Using PHP from the command line - Manual:». The PHP Group. Consultado el 11 de septiembre de 2009. [16] «PHP: PHP 5 ChangeLog». The PHP Group. 8 de noviembre de 2007. Consultado el 22 de febrero de 2008. [17] «Last 5.3 release ever available: PHP 5.3.29 - 5.3 now EOL». PHP. Consultado el 20 de septiembre de 2013. [18] «Built-in web server». Consultado el 26 de marzo de 2012. [19] «What has changed in PHP 5.5.x». Consultado el 13 de abril de 2013. [20] «Migrating from PHP 5.5.x to PHP 5.6.x». Archivado desde el original el 30 de noviembre de 2015. Consultado el 20 de septiembre de 2014. [21] «PHP 6: Features, Release Date, Hosting and Download». Consultado el 6 de mayo de 2011. [22] «Nombre de la próxima versión de PHP». Consultado el 24 de julio de 2014. [23] «RFC: PHP 7.0 Timeline». 4 de noviembre de 2015. Consultado el 4 de noviembre de 2015. [24] «Benchmarking PHPNG!». [25] «PHP RFC: Return Type Declarations». [26] «PHP: Sintaxis básica». Consultado el 13 de abril de 2013.

4.4.7

Enlaces externos

Wikilibros •

Wikilibros alberga un libro o manual sobre Programación en PHP.

• Sitio web oficial de PHP (en inglés). • PHP-by-Example Probar las funciones de PHP en línea (+500). • Tutorial extensivo de PHP y MySQL (en inglés). • Tutorial de PHP y Mysql. • Manual oficial en español. • Manuales diversos de PHP. • Insertar registros en PHP y MySQL.


82

CAPÍTULO 4. TIPOS DE LENGUAJES

4.5 Visual Basic Visual Basic es un lenguaje de programación dirigido por eventos, desarrollado por Alan Cooper para Microsoft. Este lenguaje de programación es un dialecto de BASIC, con importantes agregados. Su primera versión fue presentada en 1991, con la intención de simplificar la programación utilizando un ambiente de desarrollo que facilitó en cierta medida la programación misma. La última versión fue la 6, liberada en 1998, para la que Microsoft extendió el soporte hasta marzo de 2008. En 2001 Microsoft propuso abandonar el desarrollo basado en la API Win32 y pasar a un framework o marco común de librerías, independiente de la versión del sistema operativo, .NET Framework, a través de Visual Basic .NET (y otros lenguajes como C Sharp (C#) de fácil transición de código entre ellos); fue el sucesor de Visual Basic 6. Aunque Visual Basic es de propósito general, también provee facilidades para el desarrollo de aplicaciones de bases de datos usando Data Access Objects, Remote Data Objects o ActiveX Data Objects. Visual Basic contiene un entorno de desarrollo integrado o IDE que integra editor de textos para edición del código fuente, un depurador, un compilador (y enlazador) y un editor de interfaces gráficas o GUI.

4.5.1

Historia

Todas las versiones de Visual Basic para Windows son muy conocidas, aunque la Microsoft Visual Basic 1.0 desarrollada para el sistema operativo MS-DOS (ediciones Profesional y Estándar), que data de 1992, fue menos difundida. Esta proveía un entorno que, aunque en modo texto, incluía un diseñador de formularios en el que se podían arrastrar y soltar distintos controles. La última versión que sólo generaba aplicaciones de 16 bits fue la 3.0, y no incluía una biblioteca detallada de componentes para toda clase de usos. Durante la transición de los sistemas Windows 3.11 a Windows 95, en 1995, hizo su aparición la versión 4.0 de Visual Basic; ésta podía generar programas tanto de 16 como de 32 bits, a partir del mismo código fuente, aunque a costa de un gran aumento en el tamaño de los archivos necesarios en tiempo de ejecución (“runtime”). Además, se sustituyeron los controles denominados VBX por los nuevos OCX. Con la siguiente versión, la 5.0, se estuvo a punto de implementar por primera vez la posibilidad de compilar a código nativo, obteniendo una mejora de rendimiento considerable. Tanto esa como la sucesora 6.0 soportaban ciertas características propias de los lenguajes orientados a objetos, pero carecían de algunas importantes, tales como herencia y sobrecarga; pero, de hecho, no fue pensado como lenguaje orientado a objetos. La versión 6.0, que puede generar código ejecutable directo en 32 bits, continúa aún utilizándose masivamente, y es compatible con las últimas versiones de los sistemas Windows, como Windows 7 y Windows 8. Visual Basic evolucionó para integrar la plataforma .NET; allí perdió su propia identidad como lenguaje único adquirible, pasando a integrar un paquete de productos, llamado precisamente Microsoft .NET; dentro de ese paquete o framework se encuentra el nuevo y llamado Visual Basic .NET, que trabaja sobre el entorno Microsoft Visual Studio. Esta nueva versión del lenguaje posee profundas diferencias en la forma de programar respecto de Visual Basic 6, pero gran semejanza en su sintaxis básica. Cabe mencionar que, aunque fue menos conocido, se desarrolló también una versión gratuita de Visual Basic 5.0, orientada al desarrollo de controles y componentes; su nombre específico era Microsoft Visual Basic 5.0 Control Creation Edition (Visual Basic 5 CCE). También hubo versiones orientadas al desarrollo de aplicaciones para dispositivos móviles basados en Windows CE y Pocket PC, conocidas como Embedded (Visual Basic). Versiones • Visual Basic 1.0 para Windows se liberó en mayo de 1991. • Visual Basic 1.0 para MS-DOS fue liberada en septiembre de 1992. Poco popular, este lenguaje no era compatible con Visual Basic para Windows, ya que constituía en realidad la siguiente versión de los compiladores BASIC vigentes para DOS, denominados QuickBASIC y BASIC PDS (Profesional Development System). Usaba una interfaz de texto, con caracteres ASCII extendidos que daban la apariencia de una interfaz gráfica. • Visual Basic 2.0 fue liberado en noviembre de 1992. Venía en versiones Standard y Professional. El entorno de programación era más fácil de usar que el anterior, y su velocidad de proceso fue mejorada. En particular, los formularios se convirtieron en objetos instanciables, sentando así los conceptos fundamentales para módulos de clase, que más tarde se ofrecerían en la versión 4.


4.5. VISUAL BASIC

83

• Visual Basic 3.0 salió al mercado en verano de 1993, en versiones Standard y Profesional. Incluía la versión 1.1 de Microsoft Jet Database Engine, que permitía acceso a bases de datos Access. • Visual Basic 4.0, surgida en agosto de 1995, fue la primera versión que generaba aplicaciones tanto de 16 como de 32 bits para Windows. Había incompatibilidades entre las distintas realeases de esta versión que causaban fallas de instalación y problemas de operación. Mientras las anteriores utilizaban controles VBX, con la 4.0 se comenzaron a utilizar controles OLE en archivos OCX, que más tarde se llamarían controles ActiveX. • En febrero de 1997, Microsoft lanzó Visual Basic 5.0, versión que generaba programas de 32 bits exclusivamente. Los programadores que aún preferían desarrollar aplicaciones en 16 bits debían necesariamente utilizar VB 4.0, siendo transportables en código fuente a VB 5.0 y viceversa. En la versión 5 se tenía la posibilidad de crear controles personalizados; también permitía compilar a código ejecutable nativo de Windows, logrando con ello incrementar la velocidad de ejecución de los programas generados, más notablemente en los de cálculo. • Visual Basic 6.0, salido a mediados de 1998, muy mejorado, incrementó el número de áreas[1] e incluyó la posibilidad de crear aplicaciones basadas en Web. Microsoft retiró el soporte de VB6 en marzo de 2008, pero a pesar de ello las aplicaciones que genera son compatibles con plataformas más modernas, como Windows Vista, Windows Server 2008, Windows 7 y Windows 8.[2][3] El soporte estándar para Microsoft Visual Basic 5.7 finalizó el 31 de marzo de 2005, pero el extendido terminó en marzo de 2008.[4] La comunidad de usuarios de Visual Basic expresó su grave preocupación y se firmó una petición para mantener el producto vivo.[5] Microsoft se ha negado hasta el momento a cambiar su posición sobre el asunto. Irónicamente, en esa época (2005) se da a conocer que el software antiespía ofrecido por Microsoft, “Microsoft AntiSpyware” (parte de la GIANT Company Software), fue codificado en Visual Basic 6.0; su posterior sustituto, Windows Defender, fue reescrito en código C++.[6]

4.5.2

Características

Los compiladores de Visual Basic generan código que requiere una o más librerías de enlace dinámico para que funcione, conocidas comúnmente como DLL (sigla en inglés de dynamic-link library ); en algunos casos reside en el archivo llamado MSVBVMxy.DLL (siglas de “MicroSoft Visual Basic Virtual Machine x.y”, donde x.y es la versión) y en otros en VBRUNXXX.DLL (“Visual Basic Runtime X.XX”). Estas bibliotecas DLL proveen las funciones básicas implementadas en el lenguaje, conteniendo rutinas en código ejecutable que son cargadas bajo demanda en tiempo de ejecución. Además de las esenciales, existe un gran número de bibliotecas del tipo DLL con variedad de funciones, tales como las que facilitan el acceso a la mayoría de las funciones del sistema operativo o las que proveen medios para la integración con otras aplicaciones. Dentro del mismo Entorno de desarrollo integrado (IDE) de Visual Basic se puede ejecutar el programa que esté desarrollándose, es decir en modo intérprete (en realidad pseudo-compila el programa muy rápidamente y luego lo ejecuta, simulando la función de un intérprete puro). Desde ese entorno también se puede generar el archivo en código ejecutable (exe); ese programa así generado en disco puede luego ser ejecutado sin requerir del ambiente de programación (incluso en modo stand alone), aunque sí será necesario que las librerías DLL requeridas por la aplicación desarrollada se encuentren también instaladas en el sistema para posibilitar su ejecución. El propio Visual Basic provee soporte para empaquetado y distribución; es decir, permite generar un módulo instalador que contiene al programa ejecutable y las bibliotecas DLL necesarias para su ejecución. Con ese módulo la aplicación desarrollada se distribuye y puede ser instalada en cualquier equipo (que tenga un sistema operativo compatible). Así como bibliotecas DLL, hay numerosas aplicaciones desarrolladas por terceros que permiten disponer de variadas y múltiples funciones, incluso mejoras para el propio Visual Basic; las hay también para el empaquetado y distribución, y hasta para otorgar mayor funcionalidad al entorno de programación (IDE). Entorno de desarrollo Existe un único entorno de desarrollo para Visual Basic, desarrollado por Microsoft: Microsoft Visual Basic x.0, correspondientes a versiones desde la 2.0 hasta la 20.0, (con respectivas diferencias entre versiones del lenguaje). El entorno de desarrollo es muy similar al de otros lenguajes. Realizando una instalación típica del producto, las características básicas se presentan de la siguiente forma:


84

CAPÍTULO 4. TIPOS DE LENGUAJES • En la parte superior aparecen tres elementos, en este orden: la barra de título donde figura el nombre del proyecto en curso y su estado (diseño o ejecución); la barra de menú con 13 opciones desplegables y una barra de herramientas; esta última se puede personalizar, posibilitando la inclusión de prácticamente la totalidad de los comandos del IDE. • En la parte central, cubriendo la franja de mayor área, se encuentra el espacio de trabajo. Éste incluye y muestra las ventanas del proyecto, las vistas del código fuente de los módulos, los objetos y los controles que contienen las ventanas de la aplicación y el panel de controles. • El panel de controles, que aunque es móvil normalmente está ubicado a la derecha, por defecto cuenta con los siguientes controles: • • • • • • • • • • • • • • • • • • • •

PictureBox: Caja de imágenes Label: Etiqueta TextBox: Caja de texto Frame: Marco CommandButton: Botón de comando CheckBox: Casilla de verificación OptionButton: Botón de opción ComboBox: Lista desplegable ListBox: Lista HScrollBar: Barra de desplazamiento horizontal VScrollBar: Barra de desplazamiento vertical Timer: Temporizador DriveListBox: Lista de unidades de disco DirListBox: Lista de directorios FileListBox: Lista de archivos Shape: Figura Line: Línea Image: Imagen Data: Conexión a origen de datos OLE: Contenedor de documentos embebidos compatibles con Object Linking and Embedding

Además de los listados, se pueden agregar todo tipo de controles de terceros, y hay una gran cantidad de ellos que se proveen con el propio Visual Basic 6.0. Los controles vienen embebidos dentro de archivos con extensión OCX. • Las ventanas de proyecto, aunque móviles, se encuentran en el panel lateral derecho y contienen dos vistas principales: • El Explorador de proyectos, que muestra todos los elementos que componen el proyecto o grupos de proyectos (formularios, interfaz de controles, módulos de código, módulos de clase, etc.) • El Panel de propiedades, donde se muestran todos los atributos de los objetos, controles, formularios, información de módulos clase, entre muchos otros. • La Ventana inmediato, por defecto se encuentra en la parte inferior, aunque puede no estar visible (se presionan las teclas Ctrl+G, en ese caso, para mostrar la ventana). Esta ventana resulta una herramienta muy útil a la hora de depurar el programa o bien para realizar pruebas rápidas, ya que permite imprimir mensajes de texto desde el código y ejecutar sentencias y comandos simples inmediatamente (sólo sentencias que se puedan escribir en una sola línea). Por ejemplo, de la aplicación en curso, se puede consultar el valor de una variable o llamar a un método declarado en el módulo que se está depurando. Se puede ejecutar código “al vuelo”, por ejemplo con sentencias como:


4.5. VISUAL BASIC

85

? sqr(2)

siendo el signo ? un reemplazo natural del comando Print en Basic, al ejecutar la sentencia se mostraría por pantalla el valor de la raíz cuadrada de 2. También se pueden usar variables del propio programa, o sentencias de código tales como: Msgbox “Prueba de cuadro de mensaje de error.”, vbCritical, “Título del mensaje”

A la hora de la depuración puede ser útil para consultar el valor de variables del programa, o el código de error como: ? Err.Number

4.5.3

Objetos y eventos

Se designa como objeto cualquier elemento, por ejemplo, un formulario, una imagen, un control, tal como una caja de texto; a su vez, los objetos tienen propiedades, que en el caso de la caja de texto una es la propiedad “text” que se encarga de contener el texto que aparecerá en la caja. A los objetos se les puede asociar eventos. Un evento es la ocurrencia de un suceso, comúnmente la acción que realiza el usuario sobre el objeto, que como resultado puede, por ejemplo, provocar un cambio en alguna propiedad de un objeto. Por ejemplo: Visual Basic tiene un evento llamado KeyPress, que ocurre cuando el usuario presiona una tecla; ese evento se puede asociar a la caja de texto, y en él definirá (por programación) qué acción se tomará cuando se oprima una tecla. En síntesis, un objeto posee propiedades, responde a eventos y puede ejecutar métodos asociados a él. Algunos eventos comunes definidos en Visual Basic son: • Click: ocurre cuando se presiona y suelta un botón del mouse sobre un objeto. • DblClick: ocurre cuando se presiona y suelta dos veces un botón del mouse sobre un objeto. • DragDrop: ocurre al arrastrar y soltar un determinado objeto con el mouse. • DragOver: ocurre si una operación de arrastrar y soltar está en curso. • GotFocus: ocurre cuando un objeto recibe el control o foco, ya sea mediante una acción del usuario como hacer click en un objeto ventana, o cambiando el foco de objeto desde el programa, mediante el método SetFocus. • LostFocus: contrario al anterior, este evento ocurre cuando el objeto pierde el enfoque, sea mediante acción del usuario o efectuado desde la aplicación. • KeyDown: ocurre cuando el usuario mantiene presionada una tecla. • KeyUp: ocurre cuando el usuario deja de presionar una tecla. Este evento sucede precisamente al terminar el evento KeyDown. • KeyPress: ocurre como cuando se presiona y suelta una tecla. • MouseDown: ocurre cuando el usuario presiona un botón del mouse. • MouseUp: se produce cuando el usuario suelta el botón del mouse. • MouseMove: este evento ocurre mientras el usuario mueve o desplaza el puntero del mouse sobre un objeto. Imagínese un auto como un objeto; el auto tiene diversas propiedades como color, modelo, etc. Algunas con sólo 2 posibles valores, como encendido y apagado, incluso otras que a simple vista no se ven, como podría ser la cantidad de gasolina. Para definir el color de este objeto Auto, según Visual Basic, se haría de la siguiente manera: Auto.color = rojo y para definirle un evento podría ser como el siguiente ejemplo: Sub girarllave( ) Auto.encendido=true end sub.


86

CAPÍTULO 4. TIPOS DE LENGUAJES

4.5.4

Ejemplo de código

El siguiente fragmento de código muestra un cuadro de mensaje, en una ventana, que dice "¡Hola, mundo!": Private Sub Form_Load() MsgBox ("¡Hola, mundo!") End Sub

4.5.5

Ventajas

• Posee una curva de aprendizaje muy rápida. • Integra el diseño e implementación de formularios de Windows. • Permite usar con facilidad la plataforma de los sistemas Windows, dado que tiene acceso prácticamente total a la API de Windows, incluidas librerías actuales. • Es uno de los lenguajes de uso más extendido, por lo que resulta fácil encontrar información, documentación y fuentes para los proyectos. • Fácilmente extensible mediante librerías DLL y componentes ActiveX de otros lenguajes. • Posibilita añadir soporte para ejecución de scripts, VBScript o JScript, en las aplicaciones mediante Microsoft Script Control. • Tiene acceso a la API multimedia de DirectX (versiones 7 y 8). También está disponible, de forma no oficial, un componente para trabajar con OpenGL 1.1.[7] • Existe una versión, VBA, integrada en las aplicaciones de Microsoft Office, tanto Windows como Mac, que permite programar macros para extender y automatizar funcionalidades en documentos, hojas de cálculo y bases de datos (Access). • Si bien permite desarrollar grandes y complejas aplicaciones, también provee un entorno adecuado para realizar pequeños prototipos rápidos.

4.5.6

Desventajas

Las críticas hechas en las ediciones de Visual Basic anteriores a VB.NET son variadas;[8] se citan entre ellas: • Problema de versionado asociado con varias librerías runtime DLL, conocido como DLL Hell • Soporte pobre para programación orientada a objetos[9] • Incapacidad para crear aplicaciones multihilo, sin tener que recurrir a llamadas de la API de Windows. • Dependencia de complejas y frágiles entradas de registro COM[10] • La capacidad de utilizar controles en un sólo formulario es muy limitada en comparación a otras herramientas. DLL Hell DB, Libro Programando en Visual Basic,2002

4.5.7

Alternativas multiplataforma o externas a Windows

Existen múltiples alternativas dentro y fuera de Windows que intentan imitar este lenguaje y su mecánica de desarrollo. El más conocido y popular es Gambas: • Gambas es un proyecto libre para implementar programación visual con Basic en GNU/Linux. Está derivado principalmente de Visual Basic, adaptándose a partir de su lenguaje y su entorno de desarrollo, para implementar su propia variante, parcialmente compatible con Visual Basic, aportando y enriqueciendo con las oportunidades que brinda GNU/Linux. Otras opciones conocidas son Real Basic o PureBasic, que permiten desarrollar bajo Windows, Linux, Mac OS e independientemente. PureBasic permite desarrollar también para Amiga OS. A diferencia de Gambas, estas son soluciones comerciales y no son libres.


4.6. PYTHON

4.5.8

87

Referencias

[1] «What’s new in VB6?». www.insteptech.com. [2] Al Tenhundfeld. «Visual Basic 6.0 to be Supported on Windows 7». The Register. [3] «Support Statement for Visual Basic 6.0 on Windows Vista, Windows Server 2008 and windows 7». Msdn.microsoft.com. [4] «Product Family Life Cycle Guidelines for Visual Basic 6.0». Msdn2.microsoft.com. [5] «Petition to Microsoft». Classicvb.org. Archivado desde el original el 29 de noviembre de 2015. [6] Andrew Orlowski and Carey Bishop. «MS Anti-Spyware built on MS Abandonware». The Register. [7] «VBOpenGL type library». Archivado desde el original el 29 de noviembre de 2015. [8] Alex Homer, Dave Sussman, Rob Howard, Brian Francis, Karli Watson, Richard Anderson (2004). Professional ASP.NET 1.1. Wiley. ISBN 0764558900. [9] Marc D'Aoust. «Avoid Writing Tedious, Boring Code». Microsoft. [10] Andrew Troelsen (2008). Pro VB 2008 and the .NET 3.5 Platform: The expert’s voice in .NET. Apress. p. 5. ISBN 1590598229.

4.5.9

Enlaces externos

• Visual Basic 2005 Express Edition - Sitio web de la edición gratis de Visual Basic .NET • Service Pack 6 para Visual Basic 6.0: Paquete de redistribución de archivos de tiempo de ejecución (vbrun60sp6.exe) en Microsoft • Microsoft Visual Basic 6.0 Common Controls en Microsoft • VB 6.0 en MSDN • Visual Basic en Open Directory Project.

4.6 Python Python es un lenguaje de programación interpretado cuya filosofía hace hincapié en una sintaxis que favorezca un código legible. Se trata de un lenguaje de programación multiparadigma, ya que soporta orientación a objetos, programación imperativa y, en menor medida, programación funcional. Es un lenguaje interpretado, usa tipado dinámico y es multiplataforma. Es administrado por la Python Software Foundation. Posee una licencia de código abierto, denominada Python Software Foundation License,[1] que es compatible con la Licencia pública general de GNU a partir de la versión 2.1.1, e incompatible en ciertas versiones anteriores.

4.6.1

Historia

Python fue creado a finales de los ochenta[2] por Guido van Rossum en el Centro para las Matemáticas y la Informática (CWI, Centrum Wiskunde & Informatica), en los Países Bajos, como un sucesor del lenguaje de programación ABC, capaz de manejar excepciones e interactuar con el sistema operativo Amoeba.[3] El nombre del lenguaje proviene de la afición de su creador por los humoristas británicos Monty Python.[4] Van Rossum es el principal autor de Python, y su continuo rol central en decidir la dirección de Python es reconocido, refiriéndose a él como Benevolente Dictador Vitalicio (en inglés: Benevolent Dictator for Life, BDFL). En 1991, van Rossum publicó el código de la versión 0.9.0 en alt.sources.[5] En esta etapa del desarrollo ya estaban presentes clases con herencia, manejo de excepciones, funciones y los tipos modulares, como: str, list, dict, entre otros. Además en este lanzamiento inicial aparecía un sistema de módulos adoptado de Modula-3; van Rossum describe el módulo como “una de las mayores unidades de programación de Python”.[2] El modelo de excepciones en Python es


88

CAPÍTULO 4. TIPOS DE LENGUAJES

parecido al de Modula-3, con la adición de una cláusula else.[3] En el año 1994 se formó comp.lang.python, el foro de discusión principal de Python, marcando un hito en el crecimiento del grupo de usuarios de este lenguaje. Python alcanzó la versión 1.0 en enero de 1994. Una característica de este lanzamiento fueron las herramientas de la programación funcional: lambda, reduce, filter y map. Van Rossum explicó que “hace 12 años, Python adquirió lambda, reduce(), filter() y map(), cortesía de un hacker informático de Lisp que las extrañaba y que envió parches”.[6] El donante fue Amrit Prem; no se hace ninguna mención específica de cualquier herencia de Lisp en las notas de lanzamiento. La última versión liberada proveniente de CWI fue Python 1.2. En 1995, van Rossum continuó su trabajo en Python en la Corporation for National Research Initiatives (CNRI) en Reston, Virginia, donde lanzó varias versiones del software. Durante su estancia en CNRI, van Rossum lanzó la iniciativa Computer Programming for Everybody (CP4E), con el fin de hacer la programación más accesible a más gente, con un nivel de 'alfabetización' básico en lenguajes de programación, similar a la alfabetización básica en inglés y habilidades matemáticas necesarias por muchos trabajadores. Python tuvo un papel crucial en este proceso: debido a su orientación hacia una sintaxis limpia, ya era idóneo, y las metas de CP4E presentaban similitudes con su predecesor, ABC. El proyecto fue patrocinado por DARPA.[7] En el año 2007, el proyecto CP4E está inactivo, y mientras Python intenta ser fácil de aprender y no muy arcano en su sintaxis y semántica, alcanzando a los no-programadores, no es una preocupación activa.[8] En el año 2000, el equipo principal de desarrolladores de Python se cambió a BeOpen.com para formar el equipo BeOpen PythonLabs. CNRI pidió que la versión 1.6 fuera pública, continuando su desarrollo hasta que el equipo de desarrollo abandonó CNRI; su programa de lanzamiento y el de la versión 2.0 tenían una significativa cantidad de traslapo.[9] Python 2.0 fue el primer y único lanzamiento de BeOpen.com. Después que Python 2.0 fuera publicado por BeOpen.com, Guido van Rossum y los otros desarrolladores de PythonLabs se unieron en Digital Creations. Python 2.0 tomó una característica mayor del lenguaje de programación funcional Haskell: listas por comprensión. La sintaxis de Python para esta construcción es muy similar a la de Haskell, salvo por la preferencia de los caracteres de puntuación en Haskell, y la preferencia de Python por palabras claves alfabéticas. Python 2.0 introdujo además un sistema de recolección de basura capaz de recolectar referencias cíclicas.[9] Posterior a este doble lanzamiento, y después que van Rossum dejó CNRI para trabajar con desarrolladores de software comercial, quedó claro que la opción de usar Python con software disponible bajo GNU GPL era muy deseable. La licencia usada entonces, la Python License, incluía una cláusula estipulando que la licencia estaba gobernada por el estado de Virginia, por lo que, bajo la óptica de los abogados de Free Software Foundation (FSF), se hacía incompatible con GPL. CNRI y FSF se relacionaron para cambiar la licencia de software libre de Python para hacerla compatible con GPL. En el año 2001, van Rossum fue premiado con FSF Award for the Advancement of Free Software. Python 1.6.1 es esencialmente el mismo que Python 1.6, con unos pocos arreglos de bugs, y con una nueva licencia compatible con GPL.[1] Python 2.1 fue un trabajo derivado de Python 1.6.1, así como también de Python 2.0. Su licencia fue renombrada a: Python Software Foundation License. Todo el código, documentación y especificaciones añadidas, desde la fecha del lanzamiento de la versión alfa de Python 2.1, tiene como dueño a Python Software Foundation (PSF), una organización sin ánimo de lucro fundada en el año 2001, tomando como modelo la Apache Software Foundation.[1] Incluido en este lanzamiento fue una implementación del scoping más parecida a las reglas de static scoping (del cual Scheme es el originador).[10] Una innovación mayor en Python 2.2 fue la unificación de los tipos en Python (tipos escritos en C), y clases (tipos escritos en Python) dentro de una jerarquía. Esa unificación logró un modelo de objetos de Python puro y consistente.[11] También fueron agregados los generadores que fueron inspirados por el lenguaje Icon.[12] Las adiciones a la biblioteca estándar de Python y las decisiones sintácticas fueron influenciadas fuertemente por Java en algunos casos: el package logging,[13] introducido en la versión 2.3, está basado en log4j; el parser SAX, introducido en 2.0; el package threading,[14] cuya clase Thread expone un subconjunto de la interfaz de la clase homónima en Java.

4.6.2

Características y paradigmas

Python es un lenguaje de programación multiparadigma. Esto significa que más que forzar a los programadores a adoptar un estilo particular de programación, permite varios estilos: programación orientada a objetos, programación


4.6. PYTHON

89

imperativa y programación funcional. Otros paradigmas están soportados mediante el uso de extensiones. Python usa tipado dinámico y conteo de referencias para la administración de memoria. Una característica importante de Python es la resolución dinámica de nombres; es decir, lo que enlaza un método y un nombre de variable durante la ejecución del programa (también llamado enlace dinámico de métodos). Otro objetivo del diseño del lenguaje es la facilidad de extensión. Se pueden escribir nuevos módulos fácilmente en C o C++. Python puede incluirse en aplicaciones que necesitan una interfaz programable. Aunque la programación en Python podría considerarse en algunas situaciones hostil a la programación funcional tradicional del Lisp, existen bastantes analogías entre Python y los lenguajes minimalistas de la familia Lisp como puede ser Scheme.

4.6.3

Filosofía

Los usuarios de Python se refieren a menudo a la Filosofía Python que es bastante análoga a la filosofía de Unix. El código que sigue los principios de Python de legibilidad y transparencia se dice que es “pythonico”. Contrariamente, el código opaco u ofuscado es bautizado como “no pythonico” (“unpythonic” en inglés). Estos principios fueron famosamente descritos por el desarrollador de Python Tim Peters en El Zen de Python • Bello es mejor que feo. • Explícito es mejor que implícito. • Simple es mejor que complejo. • Complejo es mejor que complicado. • Plano es mejor que anidado. • Disperso es mejor que denso. • La legibilidad cuenta. • Los casos especiales no son tan especiales como para quebrantar las reglas. • Lo práctico gana a lo puro. • Los errores nunca deberían dejarse pasar silenciosamente. • A menos que hayan sido silenciados explícitamente. • Frente a la ambigüedad, rechaza la tentación de adivinar. • Debería haber una -y preferiblemente sólo una- manera obvia de hacerlo. • Aunque esa manera puede no ser obvia al principio a menos que usted sea holandés.[15] • Ahora es mejor que nunca. • Aunque nunca es a menudo mejor que ya mismo. • Si la implementación es difícil de explicar, es una mala idea. • Si la implementación es fácil de explicar, puede que sea una buena idea. • Los espacios de nombres (namespaces) son una gran idea ¡Hagamos más de esas cosas! Tim Peters, El Zen de Python

Desde la versión 2.1.2, Python incluye estos puntos (en su versión original en inglés) como un huevo de pascua que se muestra al ejecutar import this.[16]

4.6.4

Modo interactivo

El intérprete de Python estándar incluye un modo interactivo en el cual se escriben las instrucciones en una especie de intérprete de comandos: las expresiones pueden ser introducidas una a una, pudiendo verse el resultado de su evaluación inmediatamente, lo que da la posibilidad de probar porciones de código en el modo interactivo antes de integrarlo como parte de un programa. Esto resulta útil tanto para las personas que se están familiarizando con el lenguaje como para los programadores más avanzados.


90

CAPÍTULO 4. TIPOS DE LENGUAJES

Existen otros programas, tales como IDLE, bpython o IPython,[17] que añaden funcionalidades extra al modo interactivo, como el autocompletado de código y el coloreado de la sintaxis del lenguaje. Ejemplo del modo interactivo: >>> 1 + 1 2 >>> a = range(10) >>> print a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

4.6.5

Elementos del lenguaje

Python fue diseñado para ser leído con facilidad. Una de sus características es el uso de palabras donde otros lenguajes utilizarían símbolos. Por ejemplo, los operadores lógicos !, || y && en Python se escriben not, or y and, respectivamente. El contenido de los bloques de código (bucles, funciones, clases, etc.) es delimitado mediante espacios o tabuladores, conocidos como indentación, antes de cada línea de órdenes pertenecientes al bloque.[18] Python se diferencia así de otros lenguajes de programación que mantienen como costumbre declarar los bloques mediante un conjunto de caracteres, normalmente entre llaves {}.[19][20] Se pueden utilizar tanto espacios como tabuladores para indentar el código, pero se recomienda no mezclarlos.[21] Debido al significado sintáctico de la indentación, cada instrucción debe estar contenida en una sola línea. No obstante, si por legibilidad se quiere dividir la instrucción en varias líneas, añadiendo una barra invertida \ al final de una línea, se indica que la instrucción continúa en la siguiente. Estas instrucciones son equivalentes: Comentarios Los comentarios se pueden poner de dos formas. La primera y más apropiada para comentarios largos es utilizando la notación ''' comentario ''', tres apóstrofos de apertura y tres de cierre. La segunda notación utiliza el símbolo #, y se extienden hasta el final de la línea. El intérprete no tiene en cuenta los comentarios, lo cual es útil si deseamos poner información adicional en nuestro código como, por ejemplo, una explicación sobre el comportamiento de una sección del programa. ''' Comentario más largo en una línea en Python ''' print “Hola mundo” # También es posible añadir un comentario al final de una línea de código

Variables Las variables se definen de forma dinámica, lo que significa que no se tiene que especificar cuál es su tipo de antemano y puede tomar distintos valores en otro momento, incluso de un tipo diferente al que tenía previamente. Se usa el símbolo = para asignar valores. x = 1 x = “texto” # Esto es posible porque los tipos son asignados dinámicamente

Tipos de datos Los tipos de datos se pueden resumir en esta tabla: • Mutable: si su contenido (o dicho valor) puede cambiarse en tiempo de ejecución. • Inmutable: si su contenido (o dicho valor) no puede cambiarse en tiempo de ejecución. Listas y Tuplas • Para declarar una lista se usan los corchetes [], en cambio, para declarar una tupla se usan los paréntesis (). En ambas los elementos se separan por comas, y en el caso de las tuplas es necesario que tengan como mínimo una coma.


4.6. PYTHON

91

• Tanto las listas como las tuplas pueden contener elementos de diferentes tipos. No obstante las listas suelen usarse para elementos del mismo tipo en cantidad variable mientras que las tuplas se reservan para elementos distintos en cantidad fija. • Para acceder a los elementos de una lista o tupla se utiliza un índice entero (empezando por “0”, no por “1”). Se pueden utilizar índices negativos para acceder elementos a partir del final. • Las listas se caracterizan por ser mutables, es decir, se puede cambiar su contenido en tiempo de ejecución, mientras que las tuplas son inmutables ya que no es posible modificar el contenido una vez creada. Listas >>> lista = ["abc”, 42, 3.1415] >>> lista[0] # Acceder a un elemento por su índice 'abc' >>> lista[−1] # Acceder a un elemento usando un índice negativo 3.1415 >>> lista.append(True) # Añadir un elemento al final de la lista >>> lista ['abc', 42, 3.1415, True] >>> del lista[3] # Borra un elemento de la lista usando un índice (en este caso: True) >>> lista[0] = “xyz” # Re-asignar el valor del primer elemento de la lista >>> lista[0:2] # Mostrar los elementos de la lista del índice “0” al “2” (sin incluir este último) ['xyz', 42] >>> lista_anidada = [lista, [True, 42L]] # Es posible anidar listas >>> lista_anidada [['xyz', 42, 3.1415], [True, 42L]] >>> lista_anidada[1][0] # Acceder a un elemento de una lista dentro de otra lista (del segundo elemento, mostrar el primer elemento) True

Tuplas >>> tupla = (“abc”, 42, 3.1415) >>> tupla[0] # Acceder a un elemento por su índice 'abc' >>> del tupla[0] # No es posible borrar (ni añadir) un elemento en una tupla, lo que provocará una excepción ( Excepción ) >>> tupla[0] = “xyz” # Tampoco es posible re-asignar el valor de un elemento en una tupla, lo que también provocará una excepción ( Excepción ) >>> tupla[0:2] # Mostrar los elementos de la tupla del índice “0” al “2” (sin incluir este último) ('abc', 42) >>> tupla_anidada = (tupla, (True, 3.1415)) # También es posible anidar tuplas >>> 1, 2, 3, “abc” # Esto también es una tupla, aunque es recomendable ponerla entre paréntesis (recuerda que requiere, al menos, una coma) (1, 2, 3, 'abc') >>> (1) # Aunque entre paréntesis, esto no es una tupla, ya que no posee al menos una coma, por lo que únicamente aparecerá el valor 1 >>> (1,) # En cambio, en este otro caso, sí es una tupla (1,) >>> (1, 2) # Con más de un elemento no es necesaria la coma final (1, 2) >>> (1, 2,) # Aunque agregarla no modifica el resultado (1, 2)

Diccionarios • Para declarar un diccionario se usan las llaves {}. Contienen elementos separados por comas, donde cada elemento está formado por un par clave:valor (el símbolo : separa la clave de su valor correspondiente). • Los diccionarios son mutables, es decir, se puede cambiar el contenido de un valor en tiempo de ejecución. • En cambio, las claves de un diccionario deben ser inmutables. Esto quiere decir, por ejemplo, que no podremos usar ni listas ni diccionarios como claves. • El valor asociado a una clave puede ser de cualquier tipo de dato, incluso un diccionario. >>> diccionario = {"cadena": “abc”, “numero": 42, “lista": [True, 42L]} # Diccionario que tiene diferentes valores por cada clave, incluso una lista >>> diccionario["cadena"] # Usando una clave, se accede a su valor 'abc' >>> diccionario["lista"][0] # Acceder a un elemento de una lista dentro de un valor (del valor de la clave “lista”, mostrar el primer elemento) True >>> diccionario["cadena"] = “xyz” # Re-asignar el valor de una clave >>> diccionario["cadena"] 'xyz' >>> diccionario["decimal"] = 3.1415927 # Insertar un nuevo elemento clave:valor >>> diccionario["decimal"] 3.1415927 >>> diccionario_mixto = {"tupla": (True, 3.1415), “diccionario": diccionario} # También es posible que un valor sea un diccionario >>> diccionario_mixto["diccionario"]["lista"][1] # Acceder a un elemento dentro de una lista, que se encuentra dentro de un diccionario 42L >>> diccionario = {(“abc”,): 42} # Sí es posible que una clave sea una tupla, pues es inmutable >>> diccionario = {["abc"]: 42} # No es posible que una clave sea una lista, pues es mutable, lo que provocará una excepción ( Excepción )


92

CAPÍTULO 4. TIPOS DE LENGUAJES

Conjuntos • Los conjuntos se construyen mediante set(items) donde items es cualquier objeto iterable, como listas o tuplas. Los conjuntos no mantienen el orden ni contienen elementos duplicados. • Se suelen utilizar para eliminar duplicados de una secuencia, o para operaciones matemáticas como intersección, unión, diferencia y diferencia simétrica. >>> conjunto_inmutable = frozenset(["a”, “b”, “a"]) # Se utiliza una lista como objeto iterable >>> conjunto_inmutable frozenset(['a', 'b']) >>> conjunto1 = set(["a”, “b”, “a"]) # Primer conjunto mutable >>> conjunto1 set(['a', 'b']) >>> conjunto2 = set(["a”, “b”, “c”, “d"]) # Segundo conjunto mutable >>> conjunto2 set(['a', 'c', 'b', 'd']) # Recuerda, no mantienen el orden, como los diccionarios >>> conjunto1 & conjunto2 # Intersección set(['a', 'b']) >>> conjunto1 | conjunto2 # Unión set(['a', 'c', 'b', 'd']) >>> conjunto1 - conjunto2 # Diferencia (1) set([]) >>> conjunto2 - conjunto1 # Diferencia (2) set(['c', 'd']) >>> conjunto1 ^ conjunto2 # Diferencia simétrica set(['c', 'd'])

Listas por comprensión Una lista por comprensión (en inglés: list comprehension) es una expresión compacta para definir listas. Al igual que lambda, aparece en lenguajes funcionales. Ejemplos: >>> range(5) # La función “range” devuelve una lista, empezando en 0 y terminando con el número indicado menos uno [0, 1, 2, 3, 4] >>> [i*i for i in range(5)] # Por cada elemento del rango, lo multiplica por sí mismo y lo agrega al resultado [0, 1, 4, 9, 16] >>> lista = [(i, i + 2) for i in range(5)] >>> lista [(0, 2), (1, 3), (2, 4), (3, 5), (4, 6)]

Funciones • Las funciones se definen con la palabra clave def, seguida del nombre de la función y sus parámetros. Otra forma de escribir funciones, aunque menos utilizada, es con la palabra clave lambda (que aparece en lenguajes funcionales como Lisp). • El valor devuelto en las funciones con def será el dado con la instrucción return. def: >>> def suma(x, y = 2): ... return x + y # Retornar la suma del valor de la variable “x” y el valor de “y” ... >>> suma(4) # La variable “y” no se modifica, siendo su valor: 2 6 >>> suma(4, 10) # La variable “y” sí se modifica, siendo su nuevo valor: 10 14 lambda: >>> suma = lambda x, y = 2: x + y >>> suma(4) # La variable “y” no se modifica, siendo su valor: 2 6 >>> suma(4, 10) # La variable “y” sí se modifica, siendo su nuevo valor: 10 14

Clases • Las clases se definen con la palabra clave class, seguida del nombre de la clase y, si hereda de otra clase, el nombre de esta. • En Python 2.x es recomendable que una clase herede de “object”, en Python 3.x esto ya no hará falta. • En una clase un “método” equivale a una “función”, y un “atributo” equivale a una “variable”. • "__init__” es un método especial que se ejecuta al instanciar la clase, se usa generalmente para inicializar atributos y ejecutar métodos necesarios. Al igual que todos los métodos en Python, debe tener al menos un parámetro, generalmente se utiliza self. El resto de parámetros serán los que se indiquen al instanciar la clase.


4.6. PYTHON

93

• Los atributos que se desee que sean accesibles desde fuera de la clase se deben declarar usando self. delante del nombre. • En python no existe el concepto de encapsulación,[22] por lo que el programador debe ser responsable de asignar los valores a los atributos >>> class Persona(object): ... def __init__(self, nombre, edad): ... self.nombre = nombre # Un atributo cualquiera ... self.edad = edad # Otro atributo cualquiera ... def mostrar_edad(self): # Es necesario que, al menos, tenga un parámetro, generalmente: “self” ... print self.edad # mostrando un atributo ... def modificar_edad(self, edad): # Modificando Edad ... if edad < 0 or edad > 150: # Se comprueba que la edad no sea menor de 0 (algo imposible), ni mayor de 150 (algo realmente difícil) ... return False ... else: # Si está en el rango 0-150, entonces se modifica la variable ... self.edad = edad # Se modifica la edad ... >>> p = Persona(“Alicia”, 20) # Instanciamos la clase, como se puede ver, no se especifica el valor de “self” >>> p.nombre # La variable “nombre” del objeto sí es accesible desde fuera 'Alicia' >>> p.nombre = “Andrea” # Y por tanto, se puede cambiar su contenido >>> p.nombre 'Andrea' >>> p.mostrar_edad() # Podemos llamar a un método de la clase 20 >>> p.modificar_edad(21) # Y podemos cambiar la edad usando el método específico que hemos hecho para hacerlo de forma controlada >>> p.mostrar_edad() 21

Condicionales Una sentencia condicional (if) ejecuta su bloque de código interno sólo si se cumple cierta condición. Se define usando la palabra clave if seguida de la condición, y el bloque de código. Condiciones adicionales, si las hay, se introducen usando elif seguida de la condición y su bloque de código. Todas las condiciones se evalúan secuencialmente hasta encontrar la primera que sea verdadera, y su bloque de código asociado es el único que se ejecuta. Opcionalmente, puede haber un bloque final (la palabra clave else seguida de un bloque de código) que se ejecuta sólo cuando todas las condiciones fueron falsas. >>> verdadero = True >>> if verdadero: # No es necesario poner “verdadero == True” ... print “Verdadero” ... else: ... print “Falso” ... Verdadero >>> lenguaje = “Python” >>> if lenguaje == “C": # lenguaje no es “C”, por lo que este bloque se obviará y evaluará la siguiente condición ... print “Lenguaje de programación: C” ... elif lenguaje == “Python": # Se pueden añadir tantos bloques “elif” como se quiera ... print “Lenguaje de programación: Python” ... else: # En caso de que ninguna de las anteriores condiciones fuera cierta, se ejecutaría este bloque ... print “Lenguaje de programación: indefinido” ... Lenguaje de programación: Python >>> if verdadero and lenguaje == “Python": # Uso de “and” para comprobar que ambas condiciones son verdaderas ... print “Verdadero y Lenguaje de programación: Python” ... Verdadero y Lenguaje de programación: Python

Bucle for El bucle for es similar a foreach en otros lenguajes. Recorre un objeto iterable, como una lista, una tupla o un generador, y por cada elemento del iterable ejecuta el bloque de código interno. Se define con la palabra clave for seguida de un nombre de variable, seguido de in, seguido del iterable, y finalmente el bloque de código interno. En cada iteración, el elemento siguiente del iterable se asigna al nombre de variable especificado: >>> lista = ["a”, “b”, “c"] >>> for i in lista: # Iteramos sobre una lista, que es iterable ... print i ... a b c >>> cadena = “abcdef” >>> for i in cadena: # Iteramos sobre una cadena, que también es iterable ... print i, # Añadiendo una coma al final hacemos que no introduzca un salto de línea, sino un espacio ... a b c d e f

Bucle while El bucle while evalúa una condición y, si es verdadera, ejecuta el bloque de código interno. Continúa evaluando y ejecutando mientras la condición sea verdadera. Se define con la palabra clave while seguida de la condición, y a continuación el bloque de código interno: >>> numero = 0 >>> while numero < 10: ... print numero ... numero += 1, #un buen programador modificara las variables de control al finalizar el ciclo while ... 0 1 2 3 4 5 6 7 8 9


94

CAPÍTULO 4. TIPOS DE LENGUAJES

Módulos Existen muchas propiedades que se pueden agregar al lenguaje importando módulos, que son “minicódigos” (la mayoría escritos también en Python) que proveen de ciertas funciones y clases para realizar determinadas tareas. Un ejemplo es el módulo Tkinter, que permite crear interfaces gráficas basadas en la biblioteca Tk. Otro ejemplo es el módulo os, que provee acceso a muchas funciones del sistema operativo. Los módulos se agregan a los códigos escribiendo import seguida del nombre del módulo que queramos usar. >>> import os # Módulo que provee funciones del sistema operativo >>> os.name # Devuelve el nombre del sistema operativo 'posix' >>> os.mkdir("/tmp/ejemplo”) # Crea un directorio en la ruta especificada >>> import time # Módulo para trabajar con fechas y horas >>> time.strftime("%Y-%m-%d %H:%M:%S”) # Dándole un cierto formato, devuelve la fecha y/o hora actual '2010-08-10 18:01:17'

4.6.6

Sistema de objetos

En Python todo es un objeto (incluso las clases). Las clases, al ser objetos, son instancias de una metaclase. Python además soporta herencia múltiple y polimorfismo. >>> cadena = “abc” # Una cadena es un objeto de “str” >>> cadena.upper() # Al ser un objeto, posee sus propios métodos 'ABC' >>> lista = [True, 3.1415] # Una lista es un objeto de “list” >>> lista.append(42L) # Una lista también (al igual que todo) es un objeto, y también posee sus propios métodos >>> lista [True, 3.1415, 42L]

4.6.7

Biblioteca estándar

Python tiene una gran biblioteca estándar, usada para una diversidad de tareas. Esto viene de la filosofía “pilas incluidas” (“batteries included”) en referencia a los módulos de Python. Los módulos de la biblioteca estándar pueden mejorarse por módulos personalizados escritos tanto en C como en Python. Debido a la gran variedad de herramientas incluidas en la biblioteca estándar, combinada con la habilidad de usar lenguajes de bajo nivel como C y C++, los cuales son capaces de interactuar con otras bibliotecas, Python es un lenguaje que combina su clara sintaxis con el inmenso poder de lenguajes menos elegantes.

4.6.8

Implementaciones

Existen diversas implementaciones del lenguaje: • CPython es la implementación original, disponible para varias plataformas en el sitio oficial de Python. • IronPython es la implementación para .NET • Stackless Python es la variante de CPython que trata de no usar el stack de C (www.stackless.com) • Jython es la implementación hecha en Java • Pippy es la implementación realizada para Palm (pippy.sourceforge.net) • PyPy es una implementación de Python escrita en Python y optimizada mediante JIT (pypy.org) • ActivePython es una implementación privativa de Python con extensiones, para servidores en producción y aplicaciones de misión crítica desarrollado por ActiveState Software.

4.6.9

Diferencias entre Python 2.x y Python 3.x

El 13 de febrero de 2009[23] se lanzó una nueva versión de Python bajo el nombre clave “Python 3000” o, abreviado, “Py3K”.[24] Esta nueva versión incluye toda una serie de cambios que requieren reescribir el código de versiones anteriores. Para facilitar este proceso junto con Python 3 se ha publicado una herramienta automática llamada 2to3.[25] Una lista completa de los cambios puede encontrarse en Novedades de Python 3.0.


4.6. PYTHON

4.6.10

95

Véase también

• PyPI. Repositorio de paquetes de software de terceros para Python. • Django. Framework de desarrollo web. • CubicWeb. Framework de desarrollo web en plataforma Semántica. • Pygame. Conjunto de módulos para la creación de videojuegos en dos dimensiones. • Tkinter. Binding de la biblioteca gráfica Tcl/Tk para Python. • PyGTK. Binding de la biblioteca gráfica GTK para Python. • wxPython. Binding de la biblioteca gráfica wxWidgets para Python. • PyQt. Binding de la biblioteca gráfica Qt para Python. • PySide. Binding de la biblioteca gráfica Qt para Python por Nokia. • Plone. Sistema de gestión de contenidos. • Biopython, Colección de bibliotecas orientadas a la bioinformática para Python. • NumPy. Biblioteca que da soporte al cálculo con matrices y vectores.

4.6.11

Referencias

[1] History and License [2] The Making of Python [3] «Why was Python created in the first place?». General Python FAQ. [4] 1. Whetting Your Appetite [5] http://svn.python.org/view/python/trunk/Misc/HISTORY?view=markup&pathrev=51814 — Aviso: archivo grande. Ver el final del archivo. [6] The fate of reduce() in Python 3000 [7] Computer Programming for Everybody [8] Index of /cp4e [9] What’s New in Python 2.0 [10] PEP 227 -- Statically Nested Scopes [11] PEPs 252 and 253: Type and Class Changes [12] PEP 255: Simple Generators [13] PEP 282 -- A Logging System [14] threading — Higher-level threading interface [15] “Holandés” hace referencia a Guido van Rossum, el autor del lenguaje de programación Python, que es holandés. También hace referencia a la gran concentración de desarrolladores holandeses conocidos en relación a otras nacionalidades. [16] PEP 20 -- The Zen of Python [17] http://ipython.scipy.org/ [18] Python Software Foundation. «More control flow options». Python v2.7.8 Documentation (en inglés). Consultado el 20 de julio de 2014. [19] Eric Huss. «Function Definition». The C Library Reference Guide (en inglés). Consultado el 20 de julio de 2014.


96

CAPÍTULO 4. TIPOS DE LENGUAJES

[20] Álvarez, Miguel Ángel (2 de noviembre de 2001). «Funciones en Javascript». desarrolloweb.com (en inglés). Consultado el 20 de julio de 2014. [21] David Goodger. «Code Like a Pythonista: Idiomatic Python». Python.net (en inglés). Consultado el 20 de julio de 2014. [22] Encapsulación en Python [23] http://www.python.org/download/releases/ [24] PEP 3000 -- Python 3000 [25] 2to3 - Automated Python 2 to 3 code translation

4.6.12

Bibliografía

• Knowlton, Jim (2009). Python. tr: Fernández Vélez, María Jesús (1 edición). Anaya Multimedia-Anaya Interactiva. ISBN 978-84-415-2513-9. • Martelli, Alex (2007). Python. Guía de referencia. tr: Gorjón Salvador, Bruno (1 edición). Anaya MultimediaAnaya Interactiva. ISBN 978-84-415-2317-3.

4.6.13 •

Enlaces externos Wikimedia Commons alberga contenido multimedia sobre Python. Commons

Portal:Software Libre. Contenido relacionado con Software Libre.

Wikilibros •

Wikilibros alberga un libro o manual sobre Inmersión en Python.

• Traducción al español del tutorial oficial de Python • http://thepythonguru.com/ • Python tutorial • Libro para aprender a programar en Python • A gentle introduction to Python • Introducción a Python para científicos e ingenieros (Formato vídeo) • Python 3 para impacientes

4.7 Lenguaje ensamblador El lenguaje ensamblador, o assembler (assembly language en inglés), es un lenguaje de programación de bajo nivel para los computadores, microprocesadores, microcontroladores y otros circuitos integrados programables. Implementa una representación simbólica de los códigos de máquina binarios y otras constantes necesarias para programar una arquitectura dada de CPU y constituye la representación más directa del código máquina específico para cada arquitectura legible por un programador. Esta representación es usualmente definida por el fabricante de hardware, y está basada en los mnemónicos que simbolizan los pasos de procesamiento (las instrucciones), los registros del procesador, las posiciones de memoria y otras características del lenguaje. Un lenguaje ensamblador es por lo tanto específico de cierta arquitectura de computador física (o virtual). Esto está en contraste con la mayoría de los lenguajes de programación de alto nivel, que idealmente son portátiles. Un programa utilitario llamado ensamblador es usado para traducir sentencias del lenguaje ensamblador al código de máquina del computador objetivo. El ensamblador realiza una traducción más o menos isomorfa (un mapeo de uno a


4.7. LENGUAJE ENSAMBLADOR

97

uno) desde las sentencias mnemónicas a las instrucciones y datos de máquina. Esto está en contraste con los lenguajes de alto nivel, en los cuales una sola declaración generalmente da lugar a muchas instrucciones de máquina. Muchos sofisticados ensambladores ofrecen mecanismos adicionales para facilitar el desarrollo del programa, controlar el proceso de ensamblaje, y la ayuda de depuración. Particularmente, la mayoría de los ensambladores modernos incluyen una facilidad de macro (descrita más abajo), y se llaman macro ensambladores. Fue usado principalmente en los inicios del desarrollo de software, cuando aún no se contaba con potentes lenguajes de alto nivel y los recursos eran limitados. Actualmente se utiliza con frecuencia en ambientes académicos y de investigación, especialmente cuando se requiere la manipulación directa de hardware, alto rendimiento, o un uso de recursos controlado y reducido. También es utilizado en el desarrollo de controladores de dispositivo (en inglés, device drivers) y en el desarrollo de sistemas operativos, debido a la necesidad del acceso directo a las instrucciones de la máquina. Muchos dispositivos programables (como los microcontroladores) aún cuentan con el ensamblador como la única manera de ser manipulados.

4.7.1

Características

• El código escrito en lenguaje ensamblador posee una cierta dificultad de ser entendido ya que su estructura se acerca al lenguaje máquina, es decir, es un lenguaje de bajo nivel. • El lenguaje ensamblador es difícilmente portable, es decir, un código escrito para un microprocesador, puede necesitar ser modificado, para poder ser usado en otra máquina distinta. Al cambiar a una máquina con arquitectura diferente, generalmente es necesario reescribirlo completamente. • Los programas hechos por un programador experto en lenguaje ensamblador son generalmente mucho más rápidos y consumen menos recursos del sistema (memoria RAM y ROM) que el programa equivalente compilado desde un lenguaje de alto nivel. Al programar cuidadosamente en lenguaje ensamblador se pueden crear programas que se ejecutan más rápidamente y ocupan menos espacio que con lenguajes de alto nivel. • Con el lenguaje ensamblador se tiene un control muy preciso de las tareas realizadas por un microprocesador por lo que se pueden crear segmentos de código difíciles y/o muy ineficientes de programar en un lenguaje de alto nivel, ya que, entre otras cosas, en el lenguaje ensamblador se dispone de instrucciones del CPU que generalmente no están disponibles en los lenguajes de alto nivel. • También se puede controlar el tiempo en que tarda una rutina en ejecutarse, e impedir que se interrumpa durante su ejecución.

4.7.2

Programa ensamblador

Generalmente, un programa ensamblador (assembler en inglés) moderno crea código objeto traduciendo instrucciones mnemónicas de lenguaje ensamblador en opcodes, y resolviendo los nombres simbólicos para las localizaciones de memoria y otras entidades.[1] El uso de referencias simbólicas es una característica clave del lenguaje ensamblador, evitando tediosos cálculos y actualizaciones manuales de las direcciones después de cada modificación del programa. La mayoría de los ensambladores también incluyen facilidades de macros para realizar sustitución textual - ej. generar cortas secuencias de instrucciones como expansión en línea en vez de llamar a subrutinas. Los ensambladores son generalmente más simples de escribir que los compiladores para los lenguajes de alto nivel, y han estado disponibles desde los años 1950. Los ensambladores modernos, especialmente para las arquitecturas basadas en RISC, tales como MIPS, Sun SPARC, y HP PA-RISC, así como también para el x86 (−64), optimizan la planificación de instrucciones para explotar la segmentación del CPU eficientemente. En los compiladores para lenguajes de alto nivel, son el último paso antes de generar el código ejecutable. Número de pasos Hay dos tipos de ensambladores basados en cuántos pasos a través de la fuente son necesarios para producir el programa ejecutable. • Los ensambladores de un solo paso pasan a través del código fuente una vez y asumen que todos los símbolos serán definidos antes de cualquier instrucción que los refiera.


98

CAPÍTULO 4. TIPOS DE LENGUAJES • Los ensambladores de dos pasos crean una tabla con todos los símbolos y sus valores en el primer paso, después usan la tabla en un segundo paso para generar código. El ensamblador debe por lo menos poder determinar la longitud de cada instrucción en el primer paso para que puedan ser calculadas las direcciones de los símbolos.

La ventaja de un ensamblador de un solo paso es la velocidad, que no es tan importante como lo fue en un momento dados los avances en velocidad y capacidades del computador. La ventaja del ensamblador de dos pasos es que los símbolos pueden ser definidos dondequiera en el código fuente del programa. Esto permite a los programas ser definidos de maneras más lógicas y más significativas, haciendo los programas de ensamblador de dos pasos más fáciles de leer y mantener.[2] Ensambladores de alto nivel Los más sofisticados ensambladores de alto nivel proporcionan abstracciones del lenguaje tales como: • Estructuras de control avanzadas • Declaraciones e invocaciones de procedimientos/funciones de alto nivel • Tipos de datos abstractos de alto nivel, incluyendo las estructuras/records, uniones, clases, y conjuntos • Procesamiento de macros sofisticado (aunque está disponible en los ensambladores ordinarios desde finales de 1960 para el IBM/360, entre otras máquinas) • Características de programación orientada a objetos Uso del término Note que, en el uso profesional normal, el término ensamblador es frecuentemente usado tanto para referirse al lenguaje ensamblador como también al programa ensamblador (que convierte el código fuente escrito en el lenguaje ensamblador a código objeto que luego será enlazado para producir lenguaje de máquina). Las dos expresiones siguientes utilizan el término “ensamblador":

4.7.3

Lenguaje

El lenguaje ensamblador refleja directamente la arquitectura y las instrucciones en lenguaje de máquina de la CPU, y pueden ser muy diferentes de una arquitectura de CPU a otra. Cada arquitectura de microprocesador tiene su propio lenguaje de máquina, y en consecuencia su propio lenguaje ensamblador ya que este se encuentra muy ligado a la estructura del hardware para el cual se programa. Los microprocesadores difieren en el tipo y número de operaciones que soportan; también pueden tener diferente cantidad de registros, y distinta representación de los tipos de datos en memoria. Aunque la mayoría de los microprocesadores son capaces de cumplir esencialmente las mismas funciones, la forma en que lo hacen difiere y los respectivos lenguajes ensamblador reflejan tal diferencia. Instrucciones de CPU La mayoría de las CPU tienen más o menos los mismos grupos de instrucciones, aunque no necesariamente tienen todas las instrucciones de cada grupo. Las operaciones que se pueden realizar varían de una CPU a otra. Una CPU particular puede tener instrucciones que no tenga otro y viceversa. Los primeros microprocesadores de 8 bits no tenían operaciones para multiplicar o dividir números, por ejemplo, y había que hacer subrutinas para realizar esas operaciones. Otras CPU puede que no tengan operaciones de punto flotante y habría que hacer o conseguir bibliotecas que realicen esas operaciones. Las instrucciones de la CPU pueden agruparse, de acuerdo a su funcionalidad, en: Operaciones con enteros: (de 8, 16, 32 y 64 bits dependiendo de la arquitectura de la CPU, en los sistemas muy viejos también de 12, 18, 24, 36 y 48 bits) Estas son operaciones realizadas por la Unidad aritmético lógica de la CPU • Operaciones aritméticas. Como suma, resta, multiplicación, división, módulo, cambio de signo


4.7. LENGUAJE ENSAMBLADOR

99

• Operaciones booleanas. Operaciones lógicas bit a bit como AND, OR, XOR, NOT • Operaciones de bits. Como desplazamiento o shift lógico y rotaciones u Operadores a nivel de bits (hacia la derecha o hacia la izquierda, a través del bit del acarreo o sin él) • Comparaciones Operaciones de mover datos: Entre los registros y la memoria: Aunque la instrucción se llama “mover”, en la CPU, “mover datos” significa en realidad copiar datos, desde un origen a un destino, sin que el dato desaparezca del origen. Se pueden mover valores: • • • • • •

desde un registro a otro desde un registro a un lugar de la memoria desde un lugar de la memoria a un registro desde un lugar a otro de la memoria un valor inmediato a un registro un valor inmediato a un lugar de memoria

Operaciones de pila (stack, en inglés): • PUSH (escribe datos hacia el tope de la pila) • POP (lee datos desde el tope de la pila) Operaciones de entrada/salida: Son operaciones que mueven datos de un registro, desde y hacia un puerto; o de la memoria, desde y hacia un puerto • INPUT Lectura desde un puerto de entrada • OUTPUT Escritura hacia un puerto de salida Operaciones para el control del flujo del programa: • Llamadas y retornos de subrutinas • Llamadas y retornos de interrupciones • Saltos condicionales de acuerdo al resultado de la comparaciones • Saltos incondicionales Operaciones con números reales: El estándar para las operaciones con números reales en las CPU está definido por el IEEE 754. Una CPU puede tener operaciones de punto flotante con números reales mediante el coprocesador numérico (si lo hay), como las siguientes: • Operaciones aritméticas. Suma, resta, multiplicación, división, cambio de signo, valor absoluto, parte entera • Operaciones trascendentales • Operaciones trigonométricas. Seno, coseno, tangente, arcotangente • Operaciones con logaritmos, potencias y raíces • Otras El lenguaje ensamblador tiene mnemónicos para cada una de las instrucciones de la CPU en adición a otros mnemónicos a ser procesados por el programa ensamblador (como por ejemplo macros y otras sentencias en tiempo de ensamblado).


100

CAPÍTULO 4. TIPOS DE LENGUAJES

Ensamblado La transformación del lenguaje ensamblador en código máquina la realiza un programa ensamblador, y la traducción inversa la puede efectuar un desensamblador. A diferencia de los lenguajes de alto nivel, aquí hay usualmente una correspondencia 1 a 1 entre las instrucciones simples del ensamblador y el lenguaje de máquina. Sin embargo, en algunos casos, un ensamblador puede proveer “pseudo instrucciones” que se expanden en un código de máquina más extenso a fin de proveer la funcionalidad necesaria y simplificar la programación. Por ejemplo, para un código máquina condicional como “si X mayor o igual que”, un ensamblador puede utilizar una pseudoinstrucción al grupo “haga si menor que”, y “si = 0” sobre el resultado de la condición anterior. Los Ensambladores más completos también proveen un rico lenguaje de macros que se utiliza para generar código más complejo y secuencias de datos. Para el mismo procesador y el mismo conjunto de instrucciones de CPU, diferentes programas ensambladores pueden tener, cada uno de ellos, variaciones y diferencias en el conjunto de mnemónicos o en la sintáxis de su lenguaje ensamblador. Por ejemplo, en un lenguaje ensamblador para la arquitectura x86, se puede expresar la instrucción para mover 5 al registro AL de la siguiente manera: MOV AL, 5, mientras que para otro ensamblador para la misma arquitectura se expresaría al revés: MOV 5, AL. Ambos lenguajes ensambladores harían exactamente lo mismo, solo que está expresado de manera diferente. El primero usa la sintaxis de Intel, mientras que el segundo usa la sintaxis de AT&T El uso del ensamblador no resuelve definitivamente el problema de cómo programar un sistema basado en microprocesador de modo sencillo ya que para hacer un uso eficiente del mismo, hay que conocer a fondo el microprocesador, los registros de trabajo de que dispone, la estructura de la memoria, y muchas cosas más referentes a su estructura básica de funcionamiento. Ejemplos Un programa escrito en lenguaje ensamblador consiste en una serie de instrucciones que corresponden al flujo de órdenes ejecutables por un microprocesador. Por ejemplo, en el lenguaje ensamblador para un procesador x86: La sentencia • MOV AL, 61h Asigna el valor hexadecimal 61 (97 decimal) al registro “AL”. El programa ensamblador lee la sentencia de arriba y produce su equivalente binario en lenguaje de máquina • Binario: 10110000 01100001 (hexadecimal: B61) El mnemónico MOV es un código de operación u "opcode". El opcode es seguido por una lista de argumentos o parámetros, completando una típica instrucción de ensamblador. En el ejemplo, AL es un registro de 8 bits del procesador, al cual se le asignará el valor hexadecimal 61 especificado. El código de máquina generado por el ensamblador consiste de 2 bytes. El primer byte contiene empaquetado la instrucción MOV y el código del registro hacia donde se va a mover el dato: 1011 0000 01100001 | | | | | +---- Número 61h en binario | | | +--- Registro AL +-------- Instrucción MOV En el segundo byte se especifica el número 61h, escrito en binario como 01100001, que se asignará al registro AL, quedando la sentencia ejecutable como: • 10110000 01100001 La cual puede ser entendida y ejecutada directamente por el procesador.

4.7.4

Diseño del lenguaje


4.7. LENGUAJE ENSAMBLADOR

101

Elementos básicos Hay un grado grande de diversidad en la manera en que los autores de los ensambladores categorizan las sentencias y en la nomenclatura que usan. En particular, algunos describen cualquier cosa como pseudo-operación (pseudo-Op), con excepción del mnemónico de máquina o del mnemónico extendido. Un típico lenguaje ensamblador consiste en 3 tipos de sentencias de instrucción que son usadas para definir las operaciones del programa: • Mnemónicos de opcode • Secciones de datos • Directivas de ensamblador Mnemónicos de opcode y mnemónicos extendidos A diferencia de las instrucciones (sentencias) de los lenguajes de alto nivel, las instrucciones en el lenguaje ensamblador son generalmente muy simples. Generalmente, una mnemónico es un nombre simbólico para una sola instrucción en lenguaje de máquina ejecutable (un opcode), y hay por lo menos un mnemónico de opcode definido para cada instrucción en lenguaje de máquina. Cada instrucción consiste típicamente en una operación u opcode más cero o más operandos. La mayoría de las instrucciones refieren a un solo valor, o a un par de valores. Los operandos pueden ser inmediatos (típicamente valores de un byte, codificados en la propia instrucción), registros especificados en la instrucción, implícitos o las direcciones de los datos localizados en otra parte de la memoria. Esto está determinado por la arquitectura subyacente del procesador, el ensamblador simplemente refleja cómo trabaja esta arquitectura. Los mnemónicos extendidos son frecuentemente usados para especificar una combinación de un opcode con un operando específico, ej, el ensamblador del System/360 usa a B como un mnemónico extendido para el BC con una máscara de 15 y NOP al BC con una máscara de 0. Los mnemónicos extendidos son frecuentemente usados para soportar usos especializados de instrucciones, a menudo para propósitos no obvios con respecto al nombre de la instrucción. Por ejemplo, muchos CPU no tienen una instrucción explícita de NOP (No Operación), pero tienen instrucciones que puedan ser usadas para tal propósito. En el CPU 8086, la instrucción XCHG AX,AX (intercambia el registro AX consigo mismo) es usada para el NOP, con NOP siendo un pseudo-opcode para codificar la instrucción XCHG AX,AX. Algunos desensambladores reconocen esto y decodificarán la instrucción XCHG AX,AX como NOP. Similarmente, los ensambladores de IBM para el System/360 usan los mnemónicos extendidos NOP y NOPR con las máscaras cero para BC y BCR. Algunos ensambladores también soportan simples macroinstrucciones incorporadas que generan dos o más instrucciones de máquina. Por ejemplo, con algunos ensambladores para el Z80, la instrucción LD HL, BC genera las instrucciones LD L, C LD H, B.[3] LD HL, BC es un pseudo-opcode, que en este caso simula ser una instrucción de 16 bits, cuando se expande se producen dos instrucciones de 8 bits que equivalen a la simulada de 16 bits. Secciones de datos Hay instrucciones usadas para definir elementos de datos para manejar datos y variables. Definen el tipo de dato, la longitud y la alineación de los datos. Estas instrucciones también pueden definir si los datos están disponibles para programas exteriores (programas ensamblados separadamente) o solamente para el programa en el cual la sección de datos está definida. Algunos ensambladores clasifican estas instrucción Directivas del ensamblador Los directivas del ensamblador, también llamadas los pseudo opcodes, pseudooperaciones o pseudo-ops, son instrucciones que son ejecutadas por un ensamblador en el tiempo de ensamblado, no por un CPU en el tiempo de ejecución. Pueden hacer al ensamblado del programa dependiente de parámetros entrados por un programador, de modo que un programa pueda ser ensamblado de diferentes maneras, quizás para


102

CAPÍTULO 4. TIPOS DE LENGUAJES

diversos aplicaciones. También pueden ser usadas para manipular la presentación de un programa para hacerlo más fácil leer y mantener. Por ejemplo, las directivas pudieran ser usadas para reservar áreas de almacenamiento y opcionalmente su para asignar su contenido inicial. Los nombres de las directivas a menudo comienzan con un punto para distinguirlas de las instrucciones de máquina. Los ensambladores simbólicos le permiten a los programadores asociar nombres arbitrarios (etiquetas o símbolos) a posiciones de memoria. Usualmente, cada constante y variable tiene un nombre para que las instrucciones pueden referir a esas ubicaciones por nombre, así promoviendo el código autodocumentado. En el código ejecutable, el nombre de cada subprograma es asociado a su punto de entrada, así que cualquier llamada a un subprograma puede usar su nombre. Dentro de subprogramas, a los destinos GOTO se le dan etiquetas. Algunos ensambladores soportan símbolos locales que son léxicamente distintos de los símbolos normales (ej, el uso de “10$" como un destino GOTO). La mayoría de los ensambladores proporcionan un manejo flexible de símbolos, permitiendo a los programadores manejar diversos espacios de nombres, calcular automáticamente offsets dentro de estructuras de datos, y asignar etiquetas que refieren a valores literales o al resultado de cálculos simples realizados por el ensamblador. Las etiquetas también pueden ser usadas para inicializar constantes y variables con direcciones relocalizables. Los lenguajes ensambladores, como la mayoría de los otros lenguajes de computador, permiten que comentarios sean añadidos al código fuente, que son ignorados por el programa ensamblador. El buen uso de los comentarios es aún más importante con código ensamblador que con lenguajes de alto nivel, pues el significado y el propósito de una secuencia de instrucciones es más duro de descifrar a partir del código en sí mismo. El uso sabio de estas facilidades puede simplificar grandemente los problemas de codificar y mantener el código de bajo nivel. El código fuente de lenguaje ensamblador crudo generado por compiladores o desensambladores - código sin ningún comentario, ni símbolos con algún sentido, ni definiciones de datos - es muy difícil de leer cuando deben hacerse cambios. Macros Muchos ensambladores soportan macros predefinidas, y otras soportan macros definidas (y repetidamente redefinibles) por el programador que implican secuencias de líneas del texto en las cuales las variables y las constantes están empotradas. Esta secuencia de líneas de texto puede incluir opcodes o directivas. Una vez una macro se define, su nombre se puede usar en lugar de un mnemónico. Cuando el ensamblador procesa tal sentencia, reemplaza la sentencia por las líneas del texto asociadas a esa macro, entonces las procesa como si hubieran existido en el archivo del código fuente original (incluyendo, en algunos ensambladores, la expansión de cualquier macro que exista en el texto de reemplazo). Puesto que las macros pueden tener nombres cortos pero se expanden a varias, o de hecho, muchas líneas de código, pueden usarse para hacer que los programas en lenguaje ensamblador parezcan ser mucho más cortos, requiriendo menos líneas de código fuente, como sucede con los lenguajes de alto nivel. También se pueden usar para añadir niveles de estructura más altos a los programas ensamblador; opcionalmente introducen código de depuración empotrado vía parámetros y otras características similares. Muchos ensambladores tienen macros incorporadas (o predefinidas) para las llamadas de sistema y otras secuencias especiales de código, tales como la generación y el almacenamiento de los datos realizados a través de avanzadas operaciones bitwise y operaciones booleanas usadas en juegos, software de seguridad, gestión de datos y criptografía. Los macro ensambladores a menudo permiten a las macros tomar parámetros. Algunos ensambladores incluyen lenguajes macro muy sofisticados, incorporando elementos de lenguajes de alto nivel tales como parámetros opcionales, variables simbólicas, condiciones, manipulaciones de strings, operaciones aritméticas, todos usables durante la ejecución de una macro dada, y permitiendo a las macros guardar el contexto o intercambiar información. Así una macro puede generar un gran número de instrucciones o definiciones de datos en lenguaje ensamblador, basadas en los argumentos de la macro. Esto se podría usar para generar, por ejemplo, estructuras de datos de estilo de récord o bucles “desenrollados”, o podría generar algoritmos enteros basados en parámetros complejos. Una organización, usando lenguaje ensamblador, que ha sido fuertemente extendido usando tal suite de macros, puede ser considerada que se está trabajando en un lenguaje de alto nivel, puesto que tales programadores no están trabajando con los elementos conceptuales de más bajo nivel del computador. Las macros se usaron para adaptar sistemas de software de gran escala para clientes específicos en la era del mainframe, y también se usaron por el personal del cliente para satisfacer las necesidades de sus patrones haciendo versiones específicas de los sistemas operativos del fabricante. Esto fue hecho, por ejemplo, por los programadores de sistema


4.7. LENGUAJE ENSAMBLADOR

103

que trabajaban con el Conversational Monitor System / Virtual Machine (CMS/VM) de IBM y con los complementos real time transaction processing de IBM, CICS, Customer Information Control System, el airline/financial system que comenzó en los años 1970 y todavía corre con muchos sistemas de reservaciones computarizados (CRS) y sistemas de tarjeta de crédito de hoy. También es posible usar solamente las habilidades de procesamiento de macros de un ensamblador para generar código escrito en lenguajes completamente diferentes. Por ejemplo, para generar una versión de un programa en COBOL usando un programa macro ensamblador puro conteniendo líneas de código COBOL dentro de operadores de tiempo ensamblaje dando instrucciones al ensamblador para generar código arbitrario. Esto era porque, como en los años 1970 fue observado, el concepto de “procesamiento de macro” es independiente del concepto de “ensamblaje”, siendo el anterior, en términos modernos, más un procesamiento de textos, que una generación de código objeto. El concepto de procesamiento de macro apareció, y aparece, en el lenguaje de programación C, que soporta “instrucciones de preprocesador” de fijar variables, y hace pruebas condicionales en sus valores. Observe que a diferencia de ciertos macroprocesadores previos dentro de los ensambladores, el preprocesador de C no es Turing-completo porque carecía de la capacidad de bucle o go to, esto último permitiendo a los programas hacer bucles. A pesar del poder del procesamiento macro, éste dejó de usarse en muchos lenguajes de alto nivel (una importante excepción es C/C++) mientras que seguía siendo perenne para los ensambladores. Esto era porque muchos programadores estaban bastante confundidos por la sustitución de parámetros macro y no distinguían la diferencia entre procesamiento macro, el ensamblaje y la ejecución. La sustitución de parámetros macro es estrictamente por nombre: en el tiempo de procesamiento macro, el valor de un parámetro es sustituido textualmente por su nombre. La clase más famosa de Error de software resultantes era el uso de un parámetro que en sí mismo era una expresión y no un nombre primario cuando el escritor macro esperaba un nombre. En el macro: foo: macro a load a*b la intención era que la rutina que llama proporcionaría el nombre de una variable, y la variable o constante “global b” sería usada para multiplicar a “a”. Si foo se llama con el parámetro a-c, ocurre la expansión macro load a-c*b. Para evitar cualquier posible ambigüedad, los usuarios de macro procesadores pueden encerrar en paréntesis los parámetros formales dentro de las definiciones de macros, o las rutinas que llaman pueden envolver en paréntesis los parámetos de entrada.[4] Así, el macro correcto, con los paréntesis, sería: foo: macro a load (a)*b y su expansión, daría como resultado: load (a-c)*b El PL/I y el C/C++ ofrecen macros, pero la esta facilidad solo puede manipular texto. Por otra parte, los lenguajes homoicónicos, tales como Lisp, Prolog, y Forth, retienen el poder de los macros de lenguaje ensamblador porque pueden manipular su propio código como datos. Soporte para programación estructurada Algunos ensambladores han incorporado elementos de programación estructurada para codificar el flujo de la ejecución. El ejemplo más temprano de este acercamiento estaba en el Concept-14 macro set, originalmente propuesto por el Dr. H.D. Mills (marzo de 1970), e implementado por Marvin Kessler en la Federal Systems Division de IBM, que extendió el macro ensamblador del S/360 con bloques de control de flujo IF/ELSE/ENDIF y similares.[5] Esto era una manera de reducir o eliminar el uso de operaciones GOTO en el código en lenguaje ensamblador, uno de los principales factores que causaban código espagueti en el lenguaje ensamblador. Este acercamiento fue ampliamente aceptado a principios de los años 1980 (los últimos días del uso de lenguaje ensamblador en gran escala). Un curioso diseño fue A-natural, un ensamblador “orientado a la corriente” (stream-oriented) para los procesadores 8080/Z80[cita requerida] de Whitesmiths Ltd. (desarrolladores del sistema operativo Idris, similar al Unix), y lo que fue reportado como el primer compilador C comercial). El lenguaje fue clasificado como un ensamblador, porque trabajaba con elementos de máquina crudos tales como opcodes, registros, y referencias de memoria; pero incorporaba


104

CAPÍTULO 4. TIPOS DE LENGUAJES

una sintaxis de expresión para indicar el orden de ejecución. Los paréntesis y otros símbolos especiales, junto con construcciones de programación estructurada orientadas a bloques, controlaban la secuencia de las instrucciones generadas. A-natural fue construido como el lenguaje objeto de un compilador C, en vez de la codificación manual, pero su sintaxis lógica ganó algunos seguidores. Ha habido poca demanda aparente para ensambladores más sofisticados debido a la declinación del desarrollo de lenguaje ensamblador de larga escala.[6] A pesar de eso, todavía se están desarrollando y aplicando en casos donde las limitaciones de recursos o las particularidades en la arquitectura de sistema objetivo previenen el efectivo uso de lenguajes de alto nivel.[7]

4.7.5

Uso del lenguaje ensamblador

Perspectiva histórica Los lenguajes ensambladores fueron primero desarrollados en los años 1950, cuando fueron referidos como lenguajes de programación de segunda generación. Por ejemplo, el SOAP (Symbolic Optimal Assembly Program) era un lenguaje ensamblador de 1957 para el computador IBM 650. Los lenguajes ensambladores eliminaron mucha de la propensión a errores y del consumo de tiempo de la programación de los lenguajes de primera generación, que se necesitaba con los primeros computadores, liberando a los programadores del tedio tal como recordar códigos numéricos y cálculo de direcciones. Una vez fueron ampliamente usados para todo tipo de programación. Sin embargo, por los años 1980 (1990 en los microcomputadores), su uso había sido en gran parte suplantado por los lenguajes de alto nivel,[cita requerida] en la búsqueda de una mejorada productividad en programación. Hoy en día, aunque el lenguaje ensamblador es casi siempre manejado y generado por los compiladores, todavía se usa para la manipulación directa del hardware, acceso a instrucciones especializadas del procesador, o para resolver problemas de desempeño crítico. Los usos típicos son controladores/manejadores (drivers) de dispositivo, sistemas embebidos de bajo nivel, y sistemas de tiempo real. Históricamente, un gran número de programas han sido escritos enteramente en lenguaje ensamblador. Los sistemas operativos fueron casi exclusivamente escritos en lenguaje ensamblador hasta la aceptación amplia del lenguaje de programación C en los años 1970 y principios de los 1980. También, muchas aplicaciones comerciales fueron escritas en lenguaje ensamblador, incluyendo una gran cantidad del software escrito por grandes corporaciones para mainframes de IBM. Los lenguajes COBOL y FORTRAN eventualmente desplazaron mucho de este trabajo, aunque un número de organizaciones grandes conservaran las infraestructuras de aplicaciones en lenguaje ensamblador hasta bien entrados los años 1990. La mayoría de los primeros microcomputadores confiaron en el lenguaje ensamblador codificado a mano, incluyendo la mayoría de los sistemas operativos y de las aplicaciones grandes. Esto era porque estos sistemas tenían limitaciones severas de recursos, impusieron idiosincráticas arquitecturas de memoria y de pantalla, y proporcionaron servicios de sistema limitados y con errores. Quizás más importante era la falta de compiladores de primera clase de lenguajes de alto nivel adecuados para el uso en el microcomputador. Un factor psicológico también pudo haber jugado un papel: la primera generación de programadores de los microcomputadores conservó una actitud de aficionado de “alambres y alicates”. En un contexto más comercial, las más grandes razones para usar el lenguaje ensamblador era hacer programas con mínimo tamaño, mínima sobrecarga, mayor velocidad y confiabilidad. Los típicos ejemplos de programas grandes en lenguaje ensamblador de ese tiempo son los sistemas operativos IBM PC DOS y aplicaciones tempranas tales como la hoja de cálculo Lotus 1-2-3, y casi todos los juegos populares para la familia Atari 800 de computadores personales. Incluso en los años 1990, la mayoría de los videojuegos de consola fueron escritos en ensamblador, incluyendo la mayoría de los juegos para la Mega Drive/Genesis y el Super Nintendo Entertainment System.[cita requerida] Según algunos insiders de la industria, el lenguaje ensamblador era el mejor lenguaje de programación a usar para obtener el mejor desempeño del Sega Saturn, una consola para la cual era notoriamente desafiante desarrollar y programar juegos.[8] El popular juego de arcade NBA Jam (1993) es otro ejemplo. El ensamblador ha sido por largo trecho, el lenguaje de desarrollo primario en los computadores hogareños Commodore 64, Atari ST, así como el ZX Spectrum. Esto fue así en gran parte porque los dialectos del BASIC en estos sistemas ofrecieron insuficiente velocidad de ejecución, así como insuficientes características para aprovechar completamente el hardware disponible. Algunos sistemas, más notablemente el Amiga, incluso tienen IDEs con características de depuración y macros altamente avanzados, tales como el freeware ASM-One assembler, comparable a las del Microsoft Visual Studio (el ASM-Uno precede al Microsoft Visual Studio). El ensamblador para el VIC-20 fue escrito por Don French y publicado por French Silk. Con 1639 bytes de longitud, su


4.7. LENGUAJE ENSAMBLADOR

105

autor cree que es el más pequeño ensamblador simbólico jamás escrito. El ensamblador soportaba el direccionamiento simbólico usual y la definición de cadenas de caracteres o cadenas hexadecimales. También permitía expresiones de direcciones que podían combinarse con las operaciones de adición, substracción, multiplicación, división, AND lógico, OR lógico, y exponenciación.[9] Uso actual Siempre ha habido debates sobre la utilidad y el desempeño del lenguaje ensamblador relativo a lenguajes de alto nivel. El lenguaje ensamblador tiene nichos específicos donde es importante (ver abajo). Pero, en general, los modernos compiladores de optimización para traducir lenguajes de alto nivel en código que puede correr tan rápidamente como el lenguaje ensamblador escrito a mano, a pesar de los contraejemplos que pueden ser encontrados.[10][11][12] La complejidad de los procesadores modernos y del subsistema de memoria hace la optimización efectiva cada vez más difícil para los compiladores, así como para los programadores en ensamblador.[13][14] Adicionalmente, y para la consternación de los amantes de la eficiencia, el desempeño cada vez mayor del procesador ha significado que la mayoría de los CPU estén desocupados la mayor parte del tiempo, con retardos causados por embotellamientos predecibles tales como operaciones de entrada/salida y paginación de memoria. Esto ha hecho que la velocidad de ejecución cruda del código no sea un problema para muchos programadores. Hay algunas situaciones en las cuales los profesionales pudieran elegir utilizar el lenguaje ensamblador. Por ejemplo cuando: • Es requerido un ejecutable binario independiente (stand-alone), es decir uno que deba ejecutarse sin recursos a componentes de tiempo de ejecución o a bibliotecas asociadas con un lenguaje de alto nivel; ésta es quizás la situación más común. Son programas empotrados que solo almacenan una pequeña cantidad de memoria y el dispositivo está dirigido para hacer tareas para un simple propósito. Ejemplos consisten en teléfonos, sistemas de combustible e ignición para automóviles, sistemas de control del aire acondicionado, sistemas de seguridad, y sensores • Interactuando directamente con el hardware, por ejemplo en controladores (drivers) de dispositivo y manejadores de interrupción • usando instrucciones específicas del procesador no explotadas o disponibles por el compilador. Un ejemplo común es la instrucción de rotación bitwise en el núcleo de muchos algoritmos de cifrado • creando funciones vectorizadas para programas en lenguajes de alto nivel como C. En el lenguaje de alto nivel esto es a veces ayudado por funciones intrínsecas del compilador que mapean directamente a los mnemónicos del SIMD, pero sin embargo resulta en una conversión de ensamblador de uno a uno para un procesador de vector asociado • Es requerida la optimización extrema, ej, en un bucle interno en un algoritmo intensivo en el uso del procesador. Los programadores de juegos toman ventaja de las habilidades de las características del hardware en los sistemas, permitiendo a los juegos correr más rápidamente. También las grandes simulaciones científicas requieren algoritmos altamente optimizados, ej, álgebra lineal con BLAS o la transformada de coseno discreta (ej, la versión SIMD en ensamblador del x264,[15] (una biblioteca para codificar streams de video) • Un sistema con severas limitaciones de recursos (ej, un sistema empotrado) debe ser codificado a mano para maximizar el uso de los limitados recursos; pero esto está llegando a ser menos común a medida que el precio del procesador decrece y el desempeño mejora • No existe ningún lenguaje de alto nivel, en un procesador nuevo o especializado, por ejemplo • Escribiendo programas de tiempo real que necesitan sincronización y respuestas precisas, tales como sistemas de navegación de vuelo, y equipo médico. Por ejemplo, en un sistema fly-by-wire (vuelo por mandos eléctricos), la telemetría debe ser interpretada y hay que actuar dentro de limitaciones estrictas de tiempo. Tales sistemas deben eliminar fuentes de retrasos impredecibles, que pueden ser creados por (algunos) lenguajes interpretados, recolección de basura automática, operaciones de paginación, o multitarea preventiva. Sin embargo, algunos lenguajes de alto nivel incorporan componentes de tiempo de ejecución e interfaces de sistema operativo que pueden introducir tales retrasos. Elegir el ensamblador o lenguajes de bajo nivel para tales sistemas da a los programadores mayor visibilidad y control sobre el proceso de los detalles


106

CAPÍTULO 4. TIPOS DE LENGUAJES

• Es requerido control total sobre el ambiente, en situaciones de seguridad extremadamente alta donde nada puede darse por sentado. • Se escriben virus de computadora, bootloaders, ciertos controladores/manejadores de dispositivo, u otros elementos muy cerca del hardware o al sistema operativo de bajo nivel • Se escriben simuladores del conjunto de instrucciones para monitoreo, trazado y depuración de errores donde la sobrecarga adicional es mantenida al mínimo • Se hace ingeniería inversa en binarios existentes que pueden o no haber sido escritos originalmente en un lenguaje de alto nivel, por ejemplo al crackear la protección anticopia del software propietario. • Se hace ingeniería inversa y modificación de video juegos (también denominado ROM hacking), que es posible por medio de varios métodos. El más ampliamente implementado es alterando el código del programa a nivel de lenguaje ensamblador • Se escribe código automodificable, algo para lo que el lenguaje ensamblador se presta bien • Se escriben juegos y otros softwares para calculadoras gráficas[16] • Se escribe software compilador que genera código ensamblador, y por lo tanto los desarrolladores deben ser programadores de lenguaje ensamblador • Se escriben algoritmos criptográficos que siempre deben tomar estrictamente el mismo tiempo para ejecutar, previniendo ataques de tiempo Sin embargo, el lenguaje ensamblador es todavía enseñado en la mayoría de los programas de ciencias de la computación e ingeniería electrónica. Aunque hoy en día, pocos programadores trabajan regularmente con el lenguaje ensamblador como una herramienta, los conceptos fundamentales continúan siendo muy importantes. Tales tópicos fundamentales, como aritmética binaria, asignación de memoria, procesamiento del stack, codificación de conjunto de caracteres, procesamiento de interrupciones, y diseño de compiladores, serían duros de estudiar en detalle sin la comprensión de cómo el computador opera a nivel del hardware. Puesto que el comportamiento del computador es fundamentalmente definido por su conjunto de instrucciones, la manera lógica de aprender tales conceptos es estudiar un lenguaje ensamblador. La mayoría de los computadores modernos tienen un conjunto de instrucciones similares. Por lo tanto, estudiar un solo lenguaje ensamblador es suficiente para aprender: i) los conceptos básicos; ii) reconocer situaciones donde el uso de lenguaje ensamblador puede ser apropiado; y iii) ver cómo el código ejecutable eficiente puede ser creado por los lenguajes de alto nivel[17] Aplicaciones típicas El lenguaje ensamblador hard-coded es típicamente usado en el ROM de arranque del sistema (BIOS en los sistemas compatible IBM PC). Este código de bajo nivel es usado, entre otras cosas, para inicializar y probar el hardware del sistema antes de cargar el sistema operativo, y está almacenado en el ROM. Una vez que ha tomado lugar un cierto nivel de inicialización del hardware, la ejecución se transfiere a otro código, típicamente escrito en lenguajes de alto nivel; pero el código corriendo inmediatamente después de que es aplicada la energía usualmente está escrito en lenguaje ensamblador. Lo mismo es cierto para los boot loaders. Muchos compiladores traducen lenguajes de alto nivel a lenguaje ensamblador primero, antes de la compilación completa, permitiendo que el código en ensamblador sea visto para propósitos de depuración y optimización. Lenguajes de relativo bajo nivel, como C, con frecuencia proveen sintaxis especial para empotrar lenguaje ensamblador en cada plataforma de hardware. El código portable del sistema entonces puede usar estos componentes específicos a un procesador a través de una interface uniforme. El lenguaje ensamblador también es valioso en ingeniería inversa, puesto que muchos programas solamente son distribuidos en una forma de código de máquina. El código de máquina es usualmente fácil de trasladar hacia lenguaje ensamblador para luego ser cuidadosamente examinado en esta forma, pero es muy difícil de trasladar hacia un lenguaje de alto nivel. Herramientas como Interactive Disassembler, hacen uso extenso del desensamblador para tales propósitos. Un nicho que hace uso del lenguaje ensamblador es el demoscene. Ciertas competiciones requieren a los concursantes restringir sus creaciones a un muy pequeño tamaño (ej, 256 bytes, 1 KB, 4 KB ó 64 KB), y el lenguaje ensamblador es el lenguaje de preferencia para alcanzar este objetivo.[18] Cuando los recursos son una preocupación, es una necesidad


4.7. LENGUAJE ENSAMBLADOR

107

la codificación en ensamblador, especialmente en sistemas constreñidos por el procesamiento del CPU, como los primeros modelos del Amiga, y el Commodore 64. El código optimizado en ensamblador es escrito “a mano” por los programadores en un intento de minimizar el número de ciclos de CPU usados. Las limitaciones del CPU son tan grandes que cada ciclo cuenta. Usar tales métodos ha habilitado, a sistemas como el Commodore 64, para producir gráficos en 3D en tiempo real con efectos avanzados, una hazaña que puede ser considerada improbable o incluso imposible para un sistema con un procesador de 0.99 MHz.[cita requerida]

4.7.6

Detalles adicionales

Para un determinado computador personal, mainframe, sistema empotrado, y consola de juegos, tanto del pasado como del presente, ha sido escrito al menos uno, y posiblemente docenas de ensambladores. Para algunos ejemplos, vea la lista de ensambladores. En los sistemas Unix, el ensamblador es llamado tradicionalmente as, aunque no es un simple cuerpo de código, siendo típicamente escrito uno nuevo por cada port. Un número de variantes de Unix usan el GAS Dentro de los grupos de procesadores, cada ensamblador tiene su propio dialecto. A veces, algunos ensambladores pueden leer el dialecto de otro, por ejemplo, TASM puede leer el viejo código del MASM, pero no al revés. FASM y NASM tienen una sintaxis similar, pero cada uno soporta diferentes macros que pueden ser difícil de trasladar de uno al otro. Las cosas básicas son siempre las mismas, pero las características avanzadas serán diferentes[19] También, los lenguajes ensambladores a veces pueden ser portables a través de diferentes sistemas operativos en el mismo tipo de CPU. Las convenciones de llamadas entre los sistemas operativos con frecuencia difieren ligeramente o en nada. y con cuidado es posible ganar portabilidad en el lenguaje ensamblador, usualmente al enlazar con una biblioteca de lenguaje C que no cambia entre sistemas operativos. Un simulador de conjunto de instrucciones (que idealmente sería escrito en lenguaje ensamblador) puede, en teoría, procesar el código objeto/binario de cualquier ensamblador) para lograr la portabilidad incluso a través de plataformas (con una sobrecargue no mayor que la de un interpretador de bytecode típico). Esto es esencialmente lo que logra el microcódigo cuando una plataforma de hardware cambia internamente. Por ejemplo, muchas cosas en libc dependen del preprocesador para hacer, al programa antes de compilar, cosas que son específicas del sistema operativo o específicas del C. De hecho, algunas funciones y símbolos ni siquiera están garantizados que existan fuera del preprocesador. Peor aún, el tamaño y el orden de los campos de las estructuras, tanto como el tamaño de ciertas typedefs como off_t, no están disponibles en lenguaje ensamblador sin la ayuda de un script de configuración, y difieren incluso entre versiones de Linux, haciendo imposible portar llamadas de funciones en libc diferentes de los que toman simples enteros o punteros como parámetros. Para manejar estos problemas, el proyecto FASMLIB provee una biblioteca de lenguaje ensamblador portable para las plataformas Win32 y Linux, pero todavía está muy incompleta.[20] Algunos lenguajes de muy alto nivel, como C y Borland/Pascal, soportan ensamblado en línea, donde relativamente secciones cortas de código en ensamblador puede ser empotradas dentro del código del lenguaje de alto nivel. El lenguaje Forth comúnmente contiene un ensamblador usado para codificar palabras. La mayoría de la gente usa un emulador para depurar sus programas en lenguaje ensamblador.

4.7.7

Ejemplos de lenguaje ensamblador

Ejemplo para la arquitectura x86 El siguiente es un ejemplo del programa clásico Hola mundo escrito para la arquitectura de procesador x86 (bajo el sistema operativo DOS). ; --------------------------------------------- ; Programa que imprime un string en la pantalla ; -------------------------------------------- .model small ; modelo de memoria .stack ; segmento del stack .data ; segmento de datos Cadena1 DB 'Hola Mundo.$' ; string a imprimir (finalizado en $) .code ; segmento del código ; --------------------------------------------- ; Inicio del programa ; --------------------------------------------- programa: ; --------------------------------------------------------------------------------------------------- ; inicia el segmento de datos ; --------------------------------------------------------------------------------------------------- MOV AX, @data ; carga en AX la dirección del segmento de datos MOV DS, AX ; mueve la dirección al registro de segmento por medio de AX ; --------------------------------------------------------------------------------------------------- ; Imprime un string en pantalla ; --------------------------------------------------------------------------------------------------- MOV DX, offset Cadena1 ; mueve a DX la dirección del string a


108

CAPÍTULO 4. TIPOS DE LENGUAJES

imprimir MOV AH, 9 ; AH = código para indicar al MS DOS que imprima en la pantalla, el string en DS:DX INT 21h ; llamada al MS DOS para ejecutar la función (en este caso especificada en AH) ; --------------------------------------------------------------------------------------------------- ; Finaliza el programa ; --------------------------------------------------------------------------------------------------- INT 20h ; llamada al MS DOS para finalizar el programa end programa

Ejemplo para el computador virtual (POCA) Una selección de instrucciones para una computadora virtual[21] ) con las correspondientes direcciones de memoria en las que se ubicarán las instrucciones. Estas direcciones NO son estáticas. Cada instrucción se acompaña del código en lenguaje ensamblador generado (código objeto) que coincide con la arquitectura de computador virtual, o conjunto de instrucciones ISA.


4.7. LENGUAJE ENSAMBLADOR

109


110

CAPÍTULO 4. TIPOS DE LENGUAJES

Web cache

Linux kernel

Squid Polipo Traffic server

AppArmor SELinux Smack TOMOYO

Process Scheduler

Web server Apache Cherokee Lighttpd Nginx

Netfilter

Perl PHP Python

CPU & RAM

NIC device driver kmod-fs-ext4 kmod-fs-btrfs Lustre ...

MariaDB MySQL Drizzle

La LAMP comprende PHP (aquí con Squid).

Botnets for DDoS-attacks cracking attempts ...

Attacks

Competitors

& Requests

Network scheduler

Database

Crackers

stave off

Linux network stack

CGI scripting

Environment: CCC

Hardware

compete for customers

serve

Networking hardware

Internet Responses

Customers

low latency

Storage SATA SAS RAID iSCSI NAS

want attendance

Botnets DDoS-Attacks


4.7. LENGUAJE ENSAMBLADOR

Guido van Rossum, creador de Python, en la convenci贸n OSCON 2006

111


112

CAPÍTULO 4. TIPOS DE LENGUAJES

def add5(x): return x+5 def dotwrite(ast): nodename = getNodename() label=symbol.sym_name.get(int(ast[0]),ast[0]) print ' %s [label="%s' % (nodename, label), if isinstance(ast[1], str): if ast[1].strip(): print '= %s"];' % ast[1] else: print '"]' else: print '"];' children = [] for n, child in enumerate(ast[1:]): children.append(dotwrite(child)) print ' %s -> {' % nodename, for name in children: print '%s' % name, Código Python con coloreado de sintaxis.

Web cache

Linux kernel

Squid Polipo Traffic server

AppArmor SELinux Smack TOMOYO

Process Scheduler

Web server Apache Cherokee Lighttpd Nginx

CGI scripting Perl PHP Python

Netfilter

Environment: CCC

Hardware CPU & RAM

Crackers Botnets for DDoS-attacks cracking attempts ...

Attacks stave off

Network scheduler NIC device driver kmod-fs-ext4 kmod-fs-btrfs Lustre ...

Database MariaDB MySQL Drizzle

La LAMP comprende Python (aquí con Squid)

Competitors

& Requests

Linux network stack

compete for customers

serve

Networking hardware

Internet Responses

Customers

low latency

Storage SATA SAS RAID iSCSI NAS

want attendance

Botnets DDoS-Attacks


4.7. LENGUAJE ENSAMBLADOR

113

Python viene con “pilas incluidas”

Lenguaje de máquina del Intel 8088. El código de máquina en hexadecimal se resalta en rojo, el equivalente en lenguaje ensamblador en magenta, y las direcciones de memoria donde se encuentra el código, en azul. Abajo se ve un texto en hexadecimal y ASCII.


Capítulo 5

ANEXOS 5.1 Algoritmo En matemáticas, lógica, ciencias de la computación y disciplinas relacionadas, un algoritmo (del griego y latín, dixit algorithmus y éste a su vez del matemático persa Al-Juarismi[1] ) es un conjunto prescrito de instrucciones o reglas bien definidas, ordenadas y finitas que permite realizar una actividad mediante pasos sucesivos que no generen dudas a quien deba realizar dicha actividad.[2] Dados un estado inicial y una entrada, siguiendo los pasos sucesivos se llega a un estado final y se obtiene una solución. Los algoritmos son el objeto de estudio de la algoritmia.[1] En la vida cotidiana, se emplean algoritmos frecuentemente para resolver problemas. Algunos ejemplos son los manuales de usuario, que muestran algoritmos para usar un aparato, o las instrucciones que recibe un trabajador por parte de su patrón. Algunos ejemplos en matemática son el algoritmo de multiplicación, para calcular el producto, el algoritmo de la división para calcular el cociente de dos números, el algoritmo de Euclides para obtener el máximo común divisor de dos enteros positivos, o el método de Gauss para resolver un sistema de ecuaciones lineales.

5.1.1

Definición formal

En general, no existe ningún consenso definitivo en cuanto a la definición formal de algoritmo. Muchos autores los señalan como listas de instrucciones para resolver un cálculo o un problema abstracto, es decir, que un número finito de pasos convierten los datos de un problema (entrada) en una solución (salida).[1][2][3][4][5][6] Sin embargo cabe notar que algunos algoritmos no necesariamente tienen que terminar o resolver un problema en particular. Por ejemplo, una versión modificada de la criba de Eratóstenes que nunca termine de calcular números primos no deja de ser un algoritmo.[7] A lo largo de la historia varios autores han tratado de definir formalmente a los algoritmos utilizando modelos matemáticos. Esto fue realizado por Alonzo Church en 1936 con el concepto de “calculabilidad efectiva” basada en su cálculo lambda y por Alan Turing basándose en la máquina de Turing. Los dos enfoques son equivalentes, en el sentido en que se pueden resolver exactamente los mismos problemas con ambos enfoques.[8][9] Sin embargo, estos modelos están sujetos a un tipo particular de datos como son números, símbolos o gráficas mientras que, en general, los algoritmos funcionan sobre una vasta cantidad de estructuras de datos.[3][1] En general, la parte común en todas las definiciones se puede resumir en las siguientes tres propiedades siempre y cuando no consideremos algoritmos paralelos:[7] Tiempo secuencial. Un algoritmo funciona en tiempo discretizado –paso a paso–, definiendo así una secuencia de estados "computacionales" por cada entrada válida (la entrada son los datos que se le suministran al algoritmo antes de comenzar). Estado abstracto. Cada estado computacional puede ser descrito formalmente utilizando una estructura de primer orden y cada algoritmo es independiente de su implementación (los algoritmos son objetos abstractos) de manera que en un algoritmo las estructuras de primer orden son invariantes bajo isomorfismo. Exploración acotada. La transición de un estado al siguiente queda completamente determinada por una descripción fija y finita; es decir, entre cada estado y el siguiente solamente se puede tomar en cuenta 114


5.1. ALGORITMO

115

La lámpara no funciona

¿Está enchufada?

No

Enchufarla

¿Foco quemado?

Reemplazar el foco

No Comprar nueva lámpara Los diagramas de flujo sirven para representar algoritmos de manera gráfica.

una cantidad fija y limitada de términos del estado actual. En resumen, un algoritmo es cualquier cosa que funcione paso a paso, donde cada paso se pueda describir sin ambigüedad y sin hacer referencia a una computadora en particular, y además tiene un límite fijo en cuanto a la cantidad de datos que se pueden leer/escribir en un solo paso. Esta amplia definición abarca tanto a algoritmos prácticos como aquellos que solo funcionan en teoría, por ejemplo el método de Newton y la eliminación de Gauss-Jordan funcionan,


116

CAPÍTULO 5. ANEXOS

al menos en principio, con números de precisión infinita; sin embargo no es posible programar la precisión infinita en una computadora, y no por ello dejan de ser algoritmos.[10] En particular es posible considerar una cuarta propiedad que puede ser usada para validar la tesis de Church-Turing de que toda función calculable se puede programar en una máquina de Turing (o equivalentemente, en un lenguaje de programación suficientemente general):[10] Aritmetizabilidad. Solamente operaciones innegablemente calculables están disponibles en el paso inicial.

5.1.2

Medios de expresión de un algoritmo

Los algoritmos pueden ser expresados de muchas maneras, incluyendo al lenguaje natural, pseudocódigo, diagramas de flujo y lenguajes de programación entre otros. Las descripciones en lenguaje natural tienden a ser ambiguas y extensas. El usar pseudocódigo y diagramas de flujo evita muchas ambigüedades del lenguaje natural. Dichas expresiones son formas más estructuradas para representar algoritmos; no obstante, se mantienen independientes de un lenguaje de programación específico. La descripción de un algoritmo usualmente se hace en tres niveles: 1. Descripción de alto nivel. Se establece el problema, se selecciona un modelo matemático y se explica el algoritmo de manera verbal, posiblemente con ilustraciones y omitiendo detalles. 2. Descripción formal. Se usa pseudocódigo para describir la secuencia de pasos que encuentran la solución. 3. Implementación. Se muestra el algoritmo expresado en un lenguaje de programación específico o algún objeto capaz de llevar a cabo instrucciones. También es posible incluir un teorema que demuestre que el algoritmo es correcto, un análisis de complejidad o ambos.

Diagrama de flujo Los diagramas de flujo son descripciones gráficas de algoritmos; usan símbolos conectados con flechas para indicar la secuencia de instrucciones y están regidos por ISO. Los diagramas de flujo son usados para representar algoritmos pequeños, ya que abarcan mucho espacio y su construcción es laboriosa. Por su facilidad de lectura son usados como introducción a los algoritmos, descripción de un lenguaje y descripción de procesos a personas ajenas a la computación.

Pseudocódigo El pseudocódigo (falso lenguaje, el prefijo pseudo significa falso) es una descripción de alto nivel de un algoritmo que emplea una mezcla de lenguaje natural con algunas convenciones sintácticas propias de lenguajes de programación, como asignaciones, ciclos y condicionales, aunque no está regido por ningún estándar. Es utilizado para describir algoritmos en libros y publicaciones científicas, y como producto intermedio durante el desarrollo de un algoritmo, como los diagramas de flujo, aunque presentan una ventaja importante sobre estos, y es que los algoritmos descritos en pseudocódigo requieren menos espacio para representar instrucciones complejas. El pseudocódigo está pensado para facilitar a las personas el entendimiento de un algoritmo, y por lo tanto puede omitir detalles irrelevantes que son necesarios en una implementación. Programadores diferentes suelen utilizar convenciones distintas, que pueden estar basadas en la sintaxis de lenguajes de programación concretos. Sin embargo, el pseudocódigo, en general, es comprensible sin necesidad de conocer o utilizar un entorno de programación específico, y es a la vez suficientemente estructurado para que su implementación se pueda hacer directamente a partir de él. Así el pseudocódigo cumple con las funciones antes mencionadas para representar algo abstracto los protocolos son los lenguajes para la programación. Busque fuentes más precisas para tener mayor comprensión del tema.


5.1. ALGORITMO

117

Diagrama de flujo que expresa un algoritmo para calcular la raíz cuadrada de un número x

Sistemas formales La teoría de autómatas y la teoría de funciones recursivas proveen modelos matemáticos que formalizan el concepto de algoritmo. Los modelos más comunes son la máquina de Turing, máquina de registro y funciones μ-recursivas.


118

CAPÍTULO 5. ANEXOS

Estos modelos son tan precisos como un lenguaje máquina, careciendo de expresiones coloquiales o ambigüedad, sin embargo se mantienen independientes de cualquier computadora y de cualquier implementación. Implementación Muchos algoritmos son ideados para implementarse en un programa. Sin embargo, los algoritmos pueden ser implementados en otros medios, como una red neuronal, un circuito eléctrico o un aparato mecánico y eléctrico. Algunos algoritmos inclusive se diseñan especialmente para implementarse usando lápiz y papel. El algoritmo de multiplicación tradicional, el algoritmo de Euclides, la criba de Eratóstenes y muchas formas de resolver la raíz cuadrada son sólo algunos ejemplos. Variables Son elementos que toman valores específicos de un tipo de datos concreto. La declaración de una variable puede realizarse comenzando con var. Principalmente, existen dos maneras de otorgar valores iniciales a variables: 1. Mediante una sentencia de asignación. 2. Mediante un procedimiento de entrada de datos (por ejemplo: 'read'). Ejemplo: ... i:=1; read(n); while i < n do begin (* cuerpo del bucle *) i := i + 1 end; ... Estructuras secuenciales La estructura secuencial es aquella en la que una acción sigue a otra en secuencia. Las operaciones se suceden de tal modo que la salida de una es la entrada de la siguiente y así sucesivamente hasta el fin del proceso. La asignación de esto consiste, en el paso de valores o resultados a una zona de la memoria. Dicha zona será reconocida con el nombre de la variable que recibe el valor. La asignación se puede clasificar de la siguiente forma: 1. Simples: Consiste en pasar un valor constante a una variable (a ← 15) 2. Contador: Consiste en usarla como un verificador del número de veces que se realiza un proceso (a ← a + 1) 3. Acumulador: Consiste en usarla como un sumador en un proceso (a ← a + b) 4. De trabajo: Donde puede recibir el resultado de una operación matemática que involucre muchas variables (a ← c + b*1/2). Un ejemplo de estructura secuencial, como obtener el área de un triángulo: Inicio ... float b, h, a; printf(“Diga la base”); scanf("%f”, &b); printf(“Diga la altura”); scanf("%f”, &h); a = (b*h)/2; printf(“El área del triángulo es %f”, a) ... Fin

5.1.3

Algoritmos como funciones

Esquemática de un algoritmo solucionando un problema de ciclo hamiltoniano.

Un algoritmo se puede concebir como una función que transforma los datos de un problema (entrada) en los datos de una solución (salida). Más aun, los datos se pueden representar a su vez como secuencias de bits, y en general, de


5.1. ALGORITMO

119

símbolos cualesquiera.[1][9][11] Como cada secuencia de bits representa a un número natural (véase Sistema binario), entonces los algoritmos son en esencia funciones de los números naturales en los números naturales que sí se pueden calcular. Es decir que todo algoritmo calcula una función f : N → N donde cada número natural es la codificación de un problema o de una solución. En ocasiones los algoritmos son susceptibles de nunca terminar, por ejemplo, cuando entran a un bucle infinito. Cuando esto ocurre, el algoritmo nunca devuelve ningún valor de salida, y podemos decir que la función queda indefinida para ese valor de entrada. Por esta razón se considera que los algoritmos son funciones parciales, es decir, no necesariamente definidas en todo su dominio de definición. Cuando una función puede ser calculada por medios algorítmicos, sin importar la cantidad de memoria que ocupe o el tiempo que se tarde, se dice que dicha función es computable. No todas las funciones entre secuencias datos son computables. El problema de la parada es un ejemplo.

5.1.4

Análisis de algoritmos

Como medida de la eficiencia de un algoritmo, se suelen estudiar los recursos (memoria y tiempo) que consume el algoritmo. El análisis de algoritmos se ha desarrollado para obtener valores que de alguna forma indiquen (o especifiquen) la evolución del gasto de tiempo y memoria en función del tamaño de los valores de entrada. El análisis y estudio de los algoritmos es una disciplina de las ciencias de la computación y, en la mayoría de los casos, su estudio es completamente abstracto sin usar ningún tipo de lenguaje de programación ni cualquier otra implementación; por eso, en ese sentido, comparte las características de las disciplinas matemáticas. Así, el análisis de los algoritmos se centra en los principios básicos del algoritmo, no en los de la implementación particular. Una forma de plasmar (o algunas veces “codificar”) un algoritmo es escribirlo en pseudocódigo o utilizar un lenguaje muy simple tal como Lexico, cuyos códigos pueden estar en el idioma del programador. Algunos escritores restringen la definición de algoritmo a procedimientos que deben acabar en algún momento, mientras que otros consideran procedimientos que podrían ejecutarse eternamente sin pararse, suponiendo el caso en el que existiera algún dispositivo físico que fuera capaz de funcionar eternamente. En este último caso, la finalización con éxito del algoritmo no se podría definir como la terminación de este con una salida satisfactoria, sino que el éxito estaría definido en función de las secuencias de salidas dadas durante un periodo de vida de la ejecución del algoritmo. Por ejemplo, un algoritmo que verifica que hay más ceros que unos en una secuencia binaria infinita debe ejecutarse siempre para que pueda devolver un valor útil. Si se implementa correctamente, el valor devuelto por el algoritmo será válido, hasta que evalúe el siguiente dígito binario. De esta forma, mientras evalúa la siguiente secuencia podrán leerse dos tipos de señales: una señal positiva (en el caso de que el número de ceros sea mayor que el de unos) y una negativa en caso contrario. Finalmente, la salida de este algoritmo se define como la devolución de valores exclusivamente positivos si hay más ceros que unos en la secuencia y, en cualquier otro caso, devolverá una mezcla de señales positivas y negativas.

5.1.5

Ejemplo de algoritmo

El problema consiste en encontrar el máximo de un conjunto de números. Para un ejemplo más complejo véase Algoritmo de Euclides.

Descripción de alto nivel Dado un conjunto finito C de números, se tiene el problema de encontrar el número más grande. Sin pérdida de generalidad se puede asumir que dicho conjunto no es vacío y que sus elementos están numerados como c0 , c1 , . . . , cn . Es decir, dado un conjunto C = {c0 , c1 , . . . , cn } se pide encontrar m tal que x ≤ m para todo elemento x que pertenece al conjunto C . Para encontrar el elemento máximo, se asume que el primer elemento ( c0 ) es el máximo; luego, se recorre el conjunto y se compara cada valor con el valor del máximo número encontrado hasta ese momento. En el caso que un elemento sea mayor que el máximo, se asigna su valor al máximo. Cuando se termina de recorrer la lista, el máximo número que se ha encontrado es el máximo de todo el conjunto.


120

CAPÍTULO 5. ANEXOS

Descripción formal El algoritmo puede ser escrito de una manera más formal en el siguiente pseudocódigo: Sobre la notación: • "←" representa una asignación: m ← x significa que la variable m toma el valor de x ; • "devolver" termina el algoritmo y devuelve el valor a su derecha (en este caso, el máximo de C ). Implementación En lenguaje C++: int max(int c[], int n) { int i, m = c[0]; for (i = 1; i < n; i++) if (c[i] > m) m = c[i]; return m; }

5.1.6

Véase también

Tipos de algoritmos según su función • Algoritmo de ordenamiento • Algoritmo de búsqueda Técnicas de diseño de algoritmos • Algoritmos voraces (greedy): seleccionan los elementos más prometedores del conjunto de candidatos hasta encontrar una solución. En la mayoría de los casos la solución no es óptima. • Algoritmos paralelos: permiten la división de un problema en subproblemas de forma que se puedan ejecutar de forma simultánea en varios procesadores. • Algoritmos probabilísticos: algunos de los pasos de este tipo de algoritmos están en función de valores pseudoaleatorios. • Algoritmos determinísticos: el comportamiento del algoritmo es lineal: cada paso del algoritmo tiene únicamente un paso sucesor y otro antecesor. • Algoritmos no determinísticos: el comportamiento del algoritmo tiene forma de árbol y a cada paso del algoritmo puede bifurcarse a cualquier número de pasos inmediatamente posteriores, además todas las ramas se ejecutan simultáneamente. • Divide y vencerás: dividen el problema en subconjuntos disjuntos obteniendo una solución de cada uno de ellos para después unirlas, logrando así la solución al problema completo. • Metaheurísticas: encuentran soluciones aproximadas (no óptimas) a problemas basándose en un conocimiento anterior (a veces llamado experiencia) de los mismos. • Programación dinámica: intenta resolver problemas disminuyendo su coste computacional aumentando el coste espacial. • Ramificación y acotación: se basa en la construcción de las soluciones al problema mediante un árbol implícito que se recorre de forma controlada encontrando las mejores soluciones. • Vuelta atrás (backtracking): se construye el espacio de soluciones del problema en un árbol que se examina completamente, almacenando las soluciones menos costosas.


5.1. ALGORITMO

121

Temas relacionados • Cota inferior asintótica • Cota ajustada asintótica • Complejidad computacional • Diagramas de flujo • Diagrama Nassi-Shneiderman • Máquina de Turing Disciplinas relacionadas • Ciencias de la Computación • Análisis de algoritmos • Complejidad computacional • Informática • Inteligencia artificial • Investigación operativa • Matemáticas • Programación

5.1.7

Referencias

[1] Brassard, Gilles; Bratley, Paul (1997). Fundamentos de Algoritmia. Madrid: PRENTICE HALL. ISBN 84-89660-00-X. [2] Real Academia Española. Diccionario de la lengua española "Conjunto ordenado y finito de operaciones que permite hallar la solución de un problema." [3] Cormen, Thomas; Leiserson, Charles; Rivest, Ronald; Stein, Clifford (2009). Introduction to algorithms. Cambridge, Massachusetts: The MIT Press. ISBN 978-0-262-53305-8. [4] Ralph P. Grimaldi (1998). «Propiedades de los números enteros: Inducción matemática». Matemáticas Discreta y Combinatoria. México: Addison Wesley Longman de México. ISBN 968-444-324-2. [5] Johnsonbaugh, Richard (2005). «Introducción a la teoría de números». Matemáticas Discretas. México: PEARSON EDUCACIÓN. ISBN 970-26-0637-3. [6] Carl Reynolds & Paul Tymann (2008). Schaum’s Outline of Principles of Computer Science. McGraw-Hill. ISBN 978-007-146051-4. [7] Gurevich, Yuri (2000). «Sequential Abstract State Machines capture Sequential Algorithms». ACM Transactions on Computational Logic 1 (1). ISSN 1529-3785, 77-111. [8] John E. Savage (1987). The Complexity of Computing. Krieger Publishing Co. ISBN 089874833X. [9] Sipser, Michael (2005). Introduction to the Theory of Computation (2 edición). Course Technology. ISBN 978-0534950972. [10] Nachum Dershowitz & Yuri Gurevich (2008). «A natural axiomatization of computability and proof of Church’s Thesis». Bulletin of Symbolic Logic 14 (3). ISSN 10798986, 299-350. [11] Kelley, Dean (1995). Teoría de Autómatas y Lenguajes Formales. Prentice Hall. ISBN 0-13-497777-7.


122

5.1.8

CAPÍTULO 5. ANEXOS

Bibliografía

• Aho, A. The Design and Analysis of Computer Algorithms • Cormen, T. H., Leiserson, C. E., Rivest, R. L. y Stein, C. Introduction to Algorithms (2nd ed.) • Brassard, G. y P. Bratley. Fundamentos de Algoritmia, (ISBN 848966000X) • Knuth, D. E. The Art of Computer Programming, [quien fue también, el creador del TeX] • Mamber, U. Introduction to Algorithms. A Creative Approach • Sedgewick, R. Algorithms in C (3r ed) (también existen versiones en C++ y Java)

5.1.9

Enlaces externos

Wikilibros • •

Wikilibros alberga un libro o manual sobre Algoritmia.

Wikcionario tiene definiciones y otra información sobre algoritmo.Wikcionario

• Algoritmos para principiantes • Portal de algoritmia • Técnicas de Diseño de Algoritmos manual que explica y ejemplifica los distintos paradigmas de diseño de algoritmos. Rosa Guerequeta y Antonio Vallecillo (profesores de la Universidad de Málaga). • Transparencias de la asignatura “Esquemas Algorítmicos”, Campos, J. • Apuntes y problemas de Algorítmica por Domingo Giménez Cánovas • Curso de Diseño de Algoritmos de Carlos Pes

5.2 Estructura de datos En programación, una estructura de datos es una forma particular de organizar datos en una computadora para que pueda ser utilizado de manera eficiente. Diferentes tipos de estructuras de datos son adecuados para diferentes tipos de aplicaciones, y algunos son altamente especializados para tareas específicas. Las estructuras de datos son un medio para manejar grandes cantidades de datos de manera eficiente para usos tales como grandes bases de datos y servicios de indización de Internet. Por lo general, las estructuras de datos eficientes son clave para diseñar algoritmos eficientes. Algunos métodos formales de diseño y lenguajes de programación destacan las estructuras de datos, en lugar de los algoritmos, como el factor clave de organización en el diseño de software.

5.2.1

Descripción

Las estructuras de datos se basan generalmente en la capacidad de un ordenador para recuperar y almacenar datos en cualquier lugar de su memoria.


5.2. ESTRUCTURA DE DATOS

claves

123

función de hash

casillas 00

Pedro Pérez Ana Rojas Olga Prato

01

521-8976

02

521-1234

03 :

:

13 14

521-9655

15 Ejemplo de tabla de hash.

5.2.2

Ejemplos

Existen numerosos tipos de estructuras de datos, generalmente construidas sobre otras más simples: • Un arreglo es una serie de elementos en un orden específico, por lo general todos del mismo tipo (si bien los elementos pueden ser de casi cualquier tipo). Se accede a los elementos utilizando un entero como índice para especificar el elemento que se requiere. Las implementaciones típicas asignan palabras de memoria contiguas a los elementos de los arreglos (aunque no siempre es el caso). Los arreglos pueden cambiar de tamaño o tener una longitud fija. • Un arreglo asociativo (también llamado diccionario o mapa ) es una variante más flexible que una matriz, en la que se puede añadir y eliminar libremente pares nombre-valor. Una tabla de hash es una implementación usual de un arreglo asociativo. • Un registro (también llamado tupla o estructura) es una estructura de datos agregados. Un registro es un valor que contiene otros valores, típicamente en un número fijo y la secuencia y por lo general un índice por nombres. Los elementos de los registros generalmente son llamados campos. • Una unión es una estructura de datos que especifica cuál de una serie de tipos de datos permitidos podrá ser almacenada en sus instancias, por ejemplo flotante o entero largo. En contraste con un registro, que se podría definir para contener un flotante y un entero largo, en una unión, sólo hay un valor a la vez. Se asigna suficiente espacio para contener el tipo de datos de cualquiera de los miembros. • Un tipo variante (también llamado registro variante o unión discriminada) contiene un campo adicional que indica su tipo actual. • Un conjunto es un tipo de datos abstracto que puede almacenar valores específicos, sin orden particular y sin valores duplicados. • Un Multiconjunto es un tipo de datos abstracto que puede almacenar valores específicos, sin orden particular. A diferencia de los conjuntos, los multicunjuntos admiten repeticiones.


124

CAPÍTULO 5. ANEXOS

• Un grafo es una estructura de datos conectada compuesta por nodos. Cada nodo contiene un valor y una o más referencias a otros nodos. Los grafos pueden utilizarse para representar redes, dado que los nodos pueden referenciarse entre ellos. Las conexiones entre nodos pueden tener dirección, es decir un nodo de partida y uno de llegada. • Un árbol es un caso particular de grafo dirigido en el que no se admiten ciclos y existe un camino desde un nodo llamado raíz hasta cada uno de los otros nodos. Una colección de árboles es llamada un bosque. • Una clase es una plantilla para la creación de objetos de datos según un modelo predefinido. Las clases se utilizan como representación abstracta de conceptos, incluyen campos como los registros y operaciones que pueden consultar el valor de los campos o cambiar sus valores.

5.2.3

Soporte en los lenguajes

La mayoría de los lenguajes ensambladores y algunos lenguajes de bajo nivel, tales como BCPL, carecen de soporte de estructuras de datos. En cambio, muchos lenguajes de alto nivel y algunos lenguajes ensambladores de alto nivel, tales como MASM, tienen algún tipo de soporte incorporado para ciertas estructuras de datos, tales como los registros y arreglos. Por ejemplo, los lenguajes C y Pascal soportan estructuras y registros, respectivamente, además de arreglos y matrices multidimensionales.[1][2] La mayoría de los lenguajes de programación disponen de algún tipo de biblioteca o mecanismo que el uso de estructuras de en los programas. Los lenguajes modernos por lo general vienen con bibliotecas estándar que implementan las estructuras de datos más comunes. Ejemplos de ello son la biblioteca Standard Template Library de C++, las colecciones de Java[3] y las librerías .NET de Microsoft.

5.2.4

Estructuras de datos en programación

En programación, una estructura de datos puede ser declarada inicialmente escribiendo una palabra reservada, luego un identificador para la estructura y un nombre para cada uno de sus miembros, sin olvidar los tipos de datos que estos representan. Generalmente, cada miembro se separa con algún tipo de operador, carácter o palabra reservada. En el lenguaje de programación Pauscal, es posible crear una estructura de datos de la forma mencionada. La sintaxis básica es: Estruct Identificador, _ Miembro1:TipoDeDato, _ Miembro2:TipoDeDato, _ ... Miembro9:TipoDeDato Para acceder a los miembros de una estructura, primero se debe crear una referencia a esta, generalmente con una variable de tipo; luego se pueden editar y obtener los datos de los miembros libremente. Estruc Estructura,Miembro1:Entero,Miembro2:Cadena,Miembro3:Byte Var Variable:Estructura Variable.Miembro1 = 40000 Variable.Miembro2 = “Hola Mundo” Variable.Miembro3 = 255 Mensaje(Variable.Miembro2) ' Muestra “Hola Mundo”

5.2.5

Referencias

[1] «The GNU C Manual». Free Software Foundation. Consultado el 23 de marzo de 2016. [2] «Free Pascal: Reference Guide». Free Pascal. Consultado el =23 de marzo de 2016. [3] «Java tutorial. Trail: Collections». Oracle. Consultado el =23 de marzo de 2016.

5.2.6

Véase también

• algoritmo • lenguaje de programación • tipo de dato • unión de datos


Capítulo 6

Origen del texto y las imágenes, colaboradores y licencias 6.1 Texto • Programación Fuente: https://es.wikipedia.org/wiki/Programaci%C3%B3n?oldid=90154664 Colaboradores: Youssefsan, EL Willy, Soniautn, Sabbut, Moriel, Josmanbernal, Sauron, ManuelGR, Sanbec, Javier Carro, Dodo, Ejmeza, Fortran~eswiki, Ascánder, Rsg, Tostadora, Tano4595, Fernandomirandamuro, Jecanre, Pablomdo, Cinabrium, Porao, Elsenyor, Renabot, Richy, FAR, Mejiad, Mendocino, Digigalos, Petronas, Sicarul, Airunp, Edub, Emijrp, Magister Mathematicae, Viko~eswiki, Guanxito, Murven, Unf, Mikel Gómez, Dromero, Yrbot, Vitamine, BOTijo, Ivancp, GermanX, Jyon, Gaijin, Quiron, The Photographer, Lucascr, Jesuja, Tigerfenix, Eduardo Lima, Götz, Morza, Ciencia Al Poder, Cheveri, Chlewbot, Tomatejc, Zanaqo, Rbonvall, Electrican MV, Jstitch, BOTpolicia, Qwertyytrewqqwerty, CEM-bot, Jorgelrm, Krli2s, Laura Fiorucci, Chabacano, X.Cyclop, Salvador alc, Retama, Rosarinagazo, Antur, Dorieo, Thijs!bot, Esoya, Alvaro qc, Jonpagecr, RoyFocker, Isha, Rrmsjp, JAnDbot, Jugones55, Cmontero, Kved, Pmisiones, Mansoncc, Bboccioz, NaBUru38, Humberto, Netito777, Xsm34, Marvelshine, Nioger, Chabbot, Pólux, Biasoli, AchedDamiman, Snakeyes, Technopat, Matdrodes, Autonomia, Fernando Estel, Elabra sanchez, Lic. Armando, BlackBeast, Shooke, Lucien leGrey, Sdfk, Dinopmi, Gerakibot, SieBot, Ctrl Z, Cousteau, Ortellado, Manwë, Correogsk, 3xxx, Mafores, Yonseca, Tirithel, Jarisleif, Javierito92, Amorde2, Eduardosalg, Leonpolanco, Botito777, Petruss, Aliuk, Moucaisius, JMDC, UA31, SergioN, AVBOT, David0811, Diegusjaimes, IATG, Jjflorescueto, CarsracBot, HerculeBot, Arjuno3, Andreasmperu, Luckas-bot, Jaromero, Cata11, Roinpa, Bifus, Jotterbot, Vitucho3005, ArthurBot, SuperBraulio13, Xqbot, Jkbw, NeoTommy, Serolillo, Pedrovicenterosero, Voetius, Chester269, Albertochoa, Torrente, Botarel, BenzolBot, Stuffy, MauritsBot, TigreVMMM, MAfotBOT, Gusbelluwiki, Linux65, RedBot, AnselmiJuan, KamikazeBot, Slashcsc, Dinamik-bot, Angelito7, Ripchip Bot, Tarawa1943, GrouchoBot, EmausBot, Savh, HRoestBot, Sergio Andres Segovia, Fabian Rod, Rubpe19, Jcaraballo, ChuispastonBot, Merryt, Waka Waka, WikitanvirBot, Upc, RobotEducativo, Renly, Communities, AvicBot, Sebrev, Travelour, Acratta, Brainup, LlamaAl, EnzaiBot, Helmy oved, DavidUlquiorra, Rauletemunoz, MaKiNeoH, Ovallesoft, Xx.the.samuel.xx, Ivanretro, Addbot, Balles2601, Advarg, Tenganmemiedo, Qwerty asdfg zxcvb, Eliazibh Bojorquez, MrCharro, Jarould, Crystallizedcarbon, Eurodyne, 4lextintor, Sapristi1000, Castillo.melanii, Ks-M9 y Anónimos: 452 • Programación orientada a objetos Fuente: https://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos?oldid=90485543 Colaboradores: AstroNomo, Andre Engels, Moriel, Sauron, Pieter, Hashar, ManuelGR, Robbot, Raul2010~eswiki, Angus, Caravena, Vivero, Comae, Rosarino, Dodo, Crescent Moon, Ascánder, Sms, Elwikipedista, Tano4595, Barcex, Galio, JavierCantero, Jecanre, Ivan.Romero, MatiasBellone, Identy, Niqueco, SergioVares, Soulreaper, Joji, Airunp, Nulain, Alejolp, JMPerez, Taichi, Rembiapo pohyiete (bot), El Padrino, Dem, Funflin, Josuemb, Murven, Byj2000, Alhen, Superzerocool, Yrbot, Vitamine, BOTijo, YurikBot, Icvav, GermanX, ZeruGiran, KnightRider, The Photographer, Edwardcetera, Jesuja, Txo, Otermin, Lasneyx, Spc, Tomatejc, Aleator, Jstitch, BOTpolicia, Ál, Manawo, Chfiguer, CEM-bot, Jorgelrm, Tute, Laura Fiorucci, Mariano12 1989, X.Cyclop, Anonimato1990, Antur, Montgomery, Alvaro qc, PabloCastellano, Mahadeva, Yeza, JoaquinFerrero, IrwinSantos, Kavanagh, Cratón, Isha, Egaida, Mpeinadopa, JAnDbot, Kved, Mansoncc, Muro de Aguas, TXiKiBoT, SuperJoe, Anthemfor182, Bot-Schafter, Humberto, Netito777, Xsm34, Sirpuppet, Idioma-bot, Pólux, Jmvkrecords, Developer, Biasoli, Cinevoro, VolkovBot, Technopat, Queninosta, Nesita02, Erfil, Penguino, Matdrodes, FJJW, Etnas, Carocbax, DJ Nietzsche, Muro Bot, Edmenb, Otherox, Dj Merlin, Soynatan, SieBot, ESTEBAN ESPINOZA, Carmin, Mel 23, Manwë, Pascow, Pedro Felipe, Aleposta, Tirithel, Jmmuguerza, Locos epraix, Ing moi, Javierito92, Marcecoro, HUB, Nicop, DragonBot, Lentucky, Farisori, Estirabot, Tosin2627, Eduardosalg, Leonpolanco, Pan con queso, Pablo323, Cosmox, Furti, Poco a poco, Tonchizerodos, Alexbot, Darkicebot, Serser, Prision3ro, BodhisattvaBot, Raulshc, Açipni-Lovrij, SilvonenBot, Camilo, UA31, Abajo estaba el pez, AVBOT, David0811, Angel GN, MarcoAurelio, Carok, Diegusjaimes, DumZiBoT, CarsracBot, HerculeBot, Arjuno3, Juvalen, Andreasmperu, Luckas-bot, Spirit-Black-Wikipedista, Yonidebot, ArthurBot, Milyka, SuperBraulio13, Xqbot, Jkbw, Dreitmen, Leonardo Tadei, Pedrovicenterosero, FrescoBot, Ricardogpn, Metronomo, Botarel, BOTirithel, Hprmedina, Halfdrag, Bitman28, Marsal20, Vubo, Maaksz2, El mago de la Wiki, PatruBOT, Dinamik-bot, LilyKitty, TjBot, Akira 999, Foundling, Edslov, EmausBot, Sergio Andres Segovia, Africanus, Superbenja, J053d, Minirobots, Wrdhat, Emiduronte, MadriCR, Waka Waka, Penavarro09, Tokvo, MerlIwBot, Raymonddoyle, MetroBot, Invadibot, Bibliofilotranstornado, DLeandroc, Helmy oved, Syum90, Lautaro 97, Josefergui, Lamauro, Jean70000, Addbot, Balles2601, Hans Topo1993, Jmas131, Machado Ortiz, DarkBlueZV, Jlopezsilva, Jarould, Matiia, Crystallizedcarbon, DavidBorjaM, Vivi bos, Fernando2812l, AlmaLopezBlanco y Anónimos: 645 • Programación estructurada Fuente: https://es.wikipedia.org/wiki/Programaci%C3%B3n_estructurada?oldid=90233515 Colaboradores: Moriel, ManuelGR, Tostadora, Loco085, Lmsilva, Magister Mathematicae, Murven, RobotQuistnix, Chobot, Yrbot, DerkeNuke, BOT-Superzerocool, YurikBot, GermanX, KnightRider, Jesuja, Banfield, Pieraco, Maldoror, Haitike, BOTpolicia, CEM-bot, Jorgelrm, Jair Moreno, JMCC1, -jem-, Efegé, Antur, Fsd141, Thijs!bot, GermanC, RoyFocker, JoaquinFerrero, JAnDbot, LeinaD natipaC, TXiKiBoT, Cronos x, Rei-bot, Pólux, VolkovBot, Technopat, Marcosaedro, Jiptohej, Galandil, Erfil, Matdrodes, Elabra sanchez, Shooke,

125


126

CAPÍTULO 6. ORIGEN DEL TEXTO Y LAS IMÁGENES, COLABORADORES Y LICENCIAS

Wega~eswiki, SieBot, Loveless, Drinibot, STBot~eswiki, Mel 23, Manwë, Javierito92, Dnu72, HUB, ToePeu.bot, Damian cf, UA31, SergioN, AVBOT, MastiBot, Rizome, Ezarate, Enramos, Diegusjaimes, Arjuno3, Luckas-bot, Electrodan, ArthurBot, SuperBraulio13, Obersachsebot, Xqbot, Jkbw, Botarel, JamsJF, D'ohBot, TiriBOT, RedBot, Aquiel, PatruBOT, EmausBot, AVIADOR, ChuispastonBot, Solde9, WikitanvirBot, Invadibot, Óscar Becerril, DarafshBot, Badgov, Helmy oved, YFdyh-bot, Addbot, Balles2601, BOTito, MrCharro, Jarould y Anónimos: 181 • Programación declarativa Fuente: https://es.wikipedia.org/wiki/Programaci%C3%B3n_declarativa?oldid=88662885 Colaboradores: Abgenis, Javier Carro, Jcvp~eswiki, Rsg, Ihavenomouth, Porao, Emonnott, Acracia, Einmumu, Solaria, Ivan romero, CEM-bot, Thanos, Osepu, Antur, Resped, Fernandopcg, Clementito, JAnDbot, Vsancho, VolkovBot, AlleborgoBot, SieBot, Loveless, Luis ademir, Nerika, Arjuno3, Luckas-bot, Gacpro, Rubinbot, Hprmedina, RedBot, Grillitus, KLBot2, YFdyh-bot, Sytabaresa, Jarould y Anónimos: 21 • Programación modular Fuente: https://es.wikipedia.org/wiki/Programaci%C3%B3n_modular?oldid=89261639 Colaboradores: JorgeGG, Pieter, Emonnott, Dem, BOTijo, GermanX, Jesuja, Tomatejc, Jstitch, CEM-bot, Satanclos, Dorieo, Fsd141, VARGUX, Gerwoman, Technopat, Galandil, DJ Nietzsche, Farisori, Tosin2627, Onixmtz, VanBot, SergioN, AVBOT, Jkbw, PatruBOT, Grillitus, Solde9, Addbot, Matiia y Anónimos: 27 • Programación en pareja Fuente: https://es.wikipedia.org/wiki/Programaci%C3%B3n_en_pareja?oldid=87460001 Colaboradores: Boticario, Viko~eswiki, RobotQuistnix, Yrbot, CEM-bot, Especiales, TXiKiBoT, SieBot, LordKynos, Nicop, Farisori, Alexbot, Diegusjaimes, Arjuno3, Xqbot, EmausBot, TuHan-Bot, ChuispastonBot, WikitanvirBot, !Silent, KLBot2, Fernandoquadra, Vsanywhere y Anónimos: 10 • Programación dinámica Fuente: https://es.wikipedia.org/wiki/Programaci%C3%B3n_din%C3%A1mica?oldid=87231000 Colaboradores: Oblongo, Edub, Ricki.rg, RobotQuistnix, Alhen, Yrbot, YurikBot, GermanX, Gothmog, JRGL, Alfredobi, Tessier, CEM-bot, Especiales, Nicolasdiaz, Cuesteras, Manz, AlbertMA, Ignaciord, Nacho rd, Esf3ra, PabloCastellano, AngelHerraez, Moonrak, AntonioLG, Airen es, VolkovBot, Technopat, Bernatgs, Highsoftx980, Muro Bot, Graimito, Furti, Sgmonda, Poco a poco, Mr freeze360, HanPritcher, Cibi3d, MelancholieBot, Migueli Jordan, Andreasmperu, Luckas-bot, Lex.mercurio, SuperBraulio13, Jkbw, El+level, Guynplaine, TjBot, Alwar~eswiki, GrouchoBot, Angelherriv, EmausBot, Grillitus, Eferrante, Manubot, MerlIwBot, KLBot2, Ectofolio, Invadibot, Elvisor, Makecat-bot, Ccontrerasb y Anónimos: 67 • Programación extrema Fuente: https://es.wikipedia.org/wiki/Programaci%C3%B3n_extrema?oldid=90467380 Colaboradores: Youssefsan, Sabbut, Moriel, Frutoseco, Pieter, ManuelGR, Danidsaster, Asierra, Voise, Sms, Rsg, Tano4595, Murphy era un optimista, JavierCantero, Porao, Renabot, Guille.hoardings, Viko~eswiki, RobotQuistnix, Mikel Gómez, YurikBot, Jacm, Martingala, GermanX, Miguel.lima, KnightRider, Eskimbot, Kekkyojin, Jaguar080, Jorgechp, CEM-bot, Tute, Juan.palacio, Thijs!bot, PabloCastellano, Escarbot, Gonxoz, Isha, JAnDbot, Camoralesm, TXiKiBoT, Jmbeas, JorgeBerjano, JCX, Bucephala, Rodrigo.pina, Technopat, AlleborgoBot, Muro Bot, Kaizen2007, Drinibot, Botito777, Poco a poco, Alexbot, Rahkso, Camilo, AVBOT, J.delanoy, Diegusjaimes, Luckas-bot, Amirobot, Ptbotgourou, Xqbot, Idatacubo, Jucapac, D'ohBot, RedBot, Srgank, EmausBot, Maciejmazurk, Antonorsi, MetroBot, STANHMAL, Mardolf, Richard Lyon, Addbot, Balles2601, Lastmasta, Agabi10, Laberinto16, AtaraxioJ, Jarould y Anónimos: 94 • Lenguaje de programación Fuente: https://es.wikipedia.org/wiki/Lenguaje_de_programaci%C3%B3n?oldid=90607297 Colaboradores: AstroNomo, Carlita~eswiki, Nnss, Joseaperez, Moriel, Sauron, JorgeGG, ManuelGR, Julie, Angus, Rumpelstiltskin, Achury, Sanbec, Zwobot, Javier Carro, Scott MacLean, MiguelRdz, Dodo, Triku, Ascánder, Avm, Rsg, HHM, Cookie, Tostadora, Elwikipedista, Danakil~eswiki, Murphy era un optimista, Jsanchezes, Jarfil, Elproferoman, Melocoton, Kalcetin, Porao, Trylks, Almorca, Suruena, Balderai, Dat, Niqueco, ZackBsAs, Ilario, LeonardoRob0t, Digigalos, Zeioth, Soulreaper, Petronas, AlfonsoERomero, Airunp, JMPerez, Edub, Taichi, Rembiapo pohyiete (bot), Genba, Magister Mathematicae, Aadrover, Orgullobot~eswiki, RobotQuistnix, Gcsantiago, Platonides, Unf, LarA, Alhen, Superzerocool, Chobot, Yrbot, BOT-Superzerocool, Oscar ., Martincarr, Vitamine, Cesarsorm, Wiki-Bot, Icvav, GermanX, AalvaradoH, Indu~eswiki, KnightRider, Jesuja, Tigerfenix, Santiperez, PabloBD, Banfield, Otermin, Nowadays, Er Komandante, Spc, Tomatejc, Balix, Rbonvall, Jorgechp, Juanjo64, BOTpolicia, Qwertyytrewqqwerty, Chfiguer, CEM-bot, Jorgelrm, Krli2s, Spazer, Alex15090, Xemuj, Ignacio Icke, Retama, Baiji, Ezequiel3E, Osepu, Roberpl, JoRgE-1987, Eamezaga, Antur, Mr. Moonlight, FrancoGG, Fsd141, Juank8041, Alvaro qc, Srengel, Cansado, Mahadeva, Rata blanca, Diosa, Escarbot, RoyFocker, Eduiba, IrwinSantos, Will vm, Tintinando, Botones, Cratón, Isha, Arcibel, Mpeinadopa, JAnDbot, Thormaster, Jugones55, BelegDraug, Diego.souto, Kved, TitoPeru, Mansoncc, BetBot~eswiki, Xavigivax, Danielantonionunez, Bot-Schafter, Elisardojm, Humberto, Netito777, Amanuense, Bedwyr, Idioma-bot, Pólux, Sebado, Bucephala, AlnoktaBOT, Dusan, Cinevoro, VolkovBot, Carola-zzz, Snakeyes, Technopat, Galandil, Queninosta, Aliamondano, Pejeyo, Matdrodes, Elabra sanchez, Synthebot, House, DJ Nietzsche, Gorpik, Lucien leGrey, AlleborgoBot, Gmarinp, IIM 78, Muro Bot, Edmenb, J.M.Domingo, Komputisto, Bucho, SieBot, Mushii, Danielba894, Carlos Zeas, Cobalttempest, Rigenea, Hompis, Drinibot, Bigsus-bot, IsmaelLuceno, Mel 23, Manwë, Correogsk, Greek, Joseromerogc, BuenaGente, Mafores, Cam367, Tirithel, Jarisleif, Javierito92, HUB, FCPB, Eduardosalg, Edgarchan, Leonpolanco, Pan con queso, Alecs.bot, LordT, Descansatore, Petruss, Poco a poco, PetrohsW, Juan Mayordomo, Darkicebot, Rαge, MADAFACK, Frei sein, Raulshc, Açipni-Lovrij, Majin boo, Camilo, UA31, Inakivk, Esterdelakpaz, CharlesKnight, AVBOT, Swatnio, DayL6, David0811, J.delanoy, MarcoAurelio, JyQ, Ezarate, Diegusjaimes, MelancholieBot, Linfocito B, Sebasweee, Arjuno3, Andreasmperu, Luckas-bot, MystBot, Bob A, Roinpa, Jotterbot, Sappler, Akhran, Vic Fede, Barteik, Billinghurst, Vandal Crusher, Julio Cardmat, XZeroBot, ArthurBot, Argentinoo, Jefrcast, SuperBraulio13, Ortisa, Manuelt15, Xqbot, Jkbw, SassoBot, Dreitmen, Dan6hell66, Ricardogpn, Igna, Torrente, Adryitan, Botarel, MauritsBot, Googolplanck, Hprmedina, TobeBot, Execoot~eswiki, Palita1880, Halfdrag, Vubo, YSCO, PatruBOT, Ganímedes, Angelito7, Mr.Ajedrez, Jose1080i, Humbefa, Tarawa1943, Jorge c2010, GrouchoBot, Cesarintel, Miss Manzana, Jose1100000, Edslov, EmausBot, Savh, AVIADOR, Ingenieros instructivos, HRoestBot, Allforrous, Sergio Andres Segovia, Chope777, Rubpe19, Eroyuela, ChuispastonBot, MadriCR, Waka Waka, Cordwainer, Lcsrns, Antonorsi, Valthern, Edc.Edc, Ismaell, Jicapter, Sebrev, MetroBot, Sansgumen, Mascorria, Teclis jma, Gusama Romero, Nernix1, Acratta, Johnbot, Harpagornis, LlamaAl, Helmy oved, Erandly, Flashlack, Cyrax, Napier, Allanbot, Syum90, Fabrizotus, BLACK M0NST3R, Lautaro 97, Juanitoalcachofados, Addbot, Shinigamisajayin, Balles2601, Killtas, Patoogalvan, Davidpaisa04, DarkBlueZV, Equiz yolo swaw, HMAZZINI, Jarould, Matiia, Egis57, Geekisthebest1, Ximenacs, Die98, GustavoJota, Marian2015, Ks-M9, Maxeieh, Panadero1997, Uld jaro y Anónimos: 879 • C++ Fuente: https://es.wikipedia.org/wiki/C%2B%2B?oldid=90495535 Colaboradores: AstroNomo, Macar~eswiki, Centeno, Joseaperez, Pablo.cl, Sauron, JorgeGG, ManuelGR, Nonick, Angus, Sanbec, Zwobot, Comae, Javier Carro, Gauss, Dodo, Stoni, Levhita, Triku, Ascánder, Sms, Rsg, Tostadora, Elwikipedista, Ramjar, Robotito, Alejovivasp, Vargenau, JCCO, Toad32767, Panchurret, Benjavalero, Niqueco, Renabot, Boticario, Zeioth, Petronas, Hispa, Edub, Taichi, Rembiapo pohyiete (bot), Kitalphar, Edtruji, Neuron~eswiki, OMenda, Orgullobot~eswiki, RobotQuistnix, Tranchis, Adept~eswiki, Francosrodriguez, Alhen, LC0, Superzerocool, Chobot, Yrbot, BOT-Superzerocool, Oscar ., FlaBot, Vitamine, BOTijo, .Sergio, YurikBot, Mortadelo2005, Ivancp, Icvav, GermanX, Zam, Beto29, KnightRider, The Photographer, Hanzo86, Jesuja, Eduardo Lima, SDaniel~eswiki, Banfield, Hxxbin, George McFinnigan, Morza, Maldoror, Er Komandante, Lasneyx, KocjoBot~eswiki, Tomatejc, FIAL NV JAIOVO JP;S J, Niuweme, Ivan romero, Futbolero, Jstitch,


6.1. TEXTO

127

BOTpolicia, Ludoviko, CEM-bot, Jorgelrm, Damifb, Tute, Wfox, Ginta, Laura Fiorucci, Marc-André Aßbrock, EnWILLYado, X.Cyclop, Jjvaca, Retama, Anonimato1990, Psicodelico6, Clavec~eswiki, Mcetina, Montgomery, FrancoGG, Thijs!bot, PabloCastellano, RamiroGonzalezMaciel, Escarbot, JoaquinFerrero, Zcool, Fernando.a.gomez.f, Isha, Xoneca, Mpeinadopa, JAnDbot, Scmbg, Muro de Aguas, TXiKiBoT, ColdWind, Humberto, Netito777, Bedorlan, Jucamo, Shark-0106, Vcamacho, KanTagoff, Pólux, BL, Sebado, Biasoli, Ia027, AlnoktaBOT, Dusan, Cinevoro, Skyhack, VolkovBot, Drever, Snakeyes, Technopat, Galandil, Josell2, Matdrodes, BlackBeast, Shooke, Lucien leGrey, AlleborgoBot, Calin99, Muro Bot, Numbo3, Obazavil, SieBot, Onzalo, Danielba894, Ctrl Z, Carpem, Loveless, Obelix83, A. B. 10, Hompis, A Vázquez O., Ermey~eswiki, Belb, Maxvaz, Tirithel, Locos epraix, Jarisleif, HUB, Maximoarmijo, Piero71, Nicop, DragonBot, Eduardosalg, Botellín, Sacel, Alejandrocaro35, Botito777, LordT, Darkicebot, Açipni-Lovrij, UA31, Arlm1000, AVBOT, David0811, Kona~eswiki, LucienBOT, A ver, Skilltik, Gurulandio, Peti610bot, Diegusjaimes, Davidgutierrezalvarez, Linkcisco, Arjuno3, Luckas-bot, Nallimbot, Roinpa, FariBOT, LordboT, S3b4s5, Joseagrc, Marioxcc, Wikante, 6d23, Marxto, ArtEze, NobelBot, SuperBraulio13, Ortisa, Xqbot, Jkbw, DarkSulivan, Cally Berry, Botarel, Spyda72, Amgc56, White Master, BOTirithel, TiriBOT, Nicolapedia, Caritdf, Halfdrag, Abece, Born2bgratis, Edgardo C, Rro4785, PatruBOT, Ganímedes, D4gnu, Alex3638, Tarawa1943, Strongilocentrotus, Foundling, DiegoBM, EmausBot, Savh, ChessBOT, Sergio Andres Segovia, Adadon, Africanus, Genhuan, Grillitus, Arpabone, KLBot, UnRar, Emiduronte, Waka Waka, Rufflos, Rezabot, KLBot2, AbelNightroad26, Cyberdelic, Francy lugo, J....441111, Allan Aguilar, Eze 96ram, JoC2011, LordAlfonso, Carlos R Castro G, Helmy oved, Flashlack, YFdyh-bot, Tsunderebot, CapacitorCapaz, 2rombos, Elialbert94, Rauletemunoz, Gjprada, Legobot, Rotciv1010, Vale Espin, Vmfdez90, Balles2601, Alex9737, JacobRodrigues, Kirebyte, Jarould, Crystallizedcarbon, BenjaBot, Hector SDuarez, Jvichezguerra, VictorLopez-JC y Anónimos: 543 • Java (lenguaje de programación) Fuente: https://es.wikipedia.org/wiki/Java_(lenguaje_de_programaci%C3%B3n)?oldid=90561615 Colaboradores: Centeno, Oblongo, Sabbut, Moriel, Abgenis, Sauron, JorgeGG, Lourdes Cardenal, ManuelGR, Robbot, Guigar~eswiki, Angus, Mdiagom, Sanbec, Zwobot, Pirenne~eswiki, Comae, Zorosandro, Dodo, Pybalo, Jynus, Ascánder, Rsg, Ihavenomouth, Tano4595, Yakoo, Elproferoman, Héctor Arnau Aparicio, Aalku, Toad32767, Julioserrano, Balderai, Ecemaml, MatiasBellone, Niqueco, FAR, LeonardoRob0t, Jorgeeie, SergioVares, Boticario, Orgullomoore, DMG, Especiall~eswiki, Hispa, JMPerez, Yrithinnd, Emijrp, Rembiapo pohyiete (bot), Zeos, Edtruji, Sbassi, Magister Mathematicae, Dem, Orgullobot~eswiki, RobotQuistnix, Thr41N, Platonides, Unf, Superzerocool, Chobot, Caiserbot, Yrbot, Amadís, BOT-Superzerocool, Adrruiz, Vitamine, Palmerabollo, Mortadelo2005, Icvav, GermanX, KnightRider, Sixtop, Cucaracha, C-3POrao, Jesuja, Txo, Bizkaino, Kenshin 85, Kepler Oort, Er Komandante, Mpadilla, Tomatejc, Jarke, Uncorreotemporal, Paintman, Sucoplus, JorSol, Axxgreazz, Jorgechp, Kraft, Ivan romero, Abrego, Futbolero, Fev, Cabanyas, Jstitch, BOTpolicia, Qwertyytrewqqwerty, CEM-bot, Alejandrosilvestri, ARHEKI, Laura Fiorucci, Casidiablo, Chabacano, Rafael Morais, Especiales, Marianov, Baiji, Santhy, Psicodelico6, Roberpl, Mariano.iglesias, Ocaso, Aviguille, Llopis73, Montgomery, FrancoGG, Dangertn, Thijs!bot, Javierrami, Fernandopcg, Ñuño Martínez, Escarbot, RoyFocker, JoaquinFerrero, Locovich, TuvicBot, Isha, Bernard, JAnDbot, Jugones55, Diego.souto, Rafa3040, Muro de Aguas, CommonsDelinker, TXiKiBoT, Wpersei, Ricardo Moctezuma, HodracirK, ColdWind, Humberto, Netito777, NaSz, Jvlivs, Sirpuppet, Pólux, Snakefang, Delphidius, AlnoktaBOT, Dusan, Cinevoro, VolkovBot, Technopat, Aliamondano, Sergio Yinyang, Matdrodes, Sanmiladsl, Synthebot, Frurgr, DJ Nietzsche, Lic. Armando, BlackBeast, Shooke, Lucien leGrey, Vatelys, AlleborgoBot, Muro Bot, Peregring-lk, Roberto Blandino C, Rodrigo.paillan, Numbo3, Racso, BotMultichill, SieBot, Ctrl Z, Loveless, Moonmaryhawke, Rojoblandino, Obelix83, Prugo, A. B. 10, Cousteau, Drinibot, BOTarate, Alex Buzeta, STBot~eswiki, Malfer, Greek, Ermey~eswiki, Piztu, BuenaGente, ProfesorFalken, Belb, DorganBot, Torturo, Locos epraix, Jarisleif, Javierito92, Marcecoro, MetsBot~eswiki, Luis.bernal, DragonBot, Benek~eswiki, Farisori, PixelBot, Estirabot, Eduardosalg, Stoleman, Botellín, Leonpolanco, Hades87, Furti, Alexbot, CestBOT, Juan Mayordomo, AlfredoMorales, Dr. Ricardo, Estebancabezudo, Toolserver, Açipni-Lovrij, Mike.lifeguard, Kroji, Ceballwiki, Camilo, UA31, AVBOT, LucienBOT, MastiBot, Angel GN, NicolasAlejandro, Speedplus, Diegusjaimes, Whibla, DumZiBoT, MelancholieBot, Linfocito B, Innv, Franxiscokafran, Morbazan, HerculeBot, Arjuno3, Saloca, Alqadim, Argentumm, Andreasmperu, Luckas-bot, Chiro79, Nallimbot, FariBOT, Jotterbot, Joseagrc, Koko10ar, Yonidebot, Rbuj, ArthurBot, SuperBraulio13, Diegatxo, Ortisa, Xqbot, Jkbw, Rubinbot, Josemiguel93, Ing.hllanos, FrescoBot, Nicoavn, Adryitan, Botarel, AstaBOTh15, Panderine!, TiriBOT, TobeBot, Nicolapedia, RedBot, Kizar, Marsal20, Vubo, DixonDBot, HUBOT, Dinamikbot, Humbefa, Tarawa1943, Waeswaes, DiegoBM, EmausBot, Savh, ZéroBot, HRoestBot, Genhuan, Grillitus, Writkas, Bettinaberries, ChuispastonBot, Solde9, Waka Waka, WikitanvirBot, Diamondland, Denis32crack, Patrias, Hiperfelix, Juancvasconez, Hugg~eswiki, Xerox 5B, Jolusafe5, MerlIwBot, KLBot2, CésarGuti, AvicBot, Almario 7, Sebrev, Tuxiano felipe, MetroBot, Invadibot, Federicotg, Pablopv98, Jacobofandebillgates, Luigi1993ify, Doubledragon, Amgomude, Infosalle2011, Vigilante Satan, Batman325, Minsbot, Dlorah, Vetranio, Elvisor, Sanderaco, Theremigue, Santga, DLeandroc, Helmy oved, Fpelliccioni, Flashlack, RosenJax, YFdyh-bot, Cristian orioles, 2rombos, Adonaybn, Fevero, Ljfeliu, Leitoxx, TToniii, Vale Espin, Addbot, Jaormazabal, Elmatoguevero, ConnieGB, Mario.porras33, Saburto, JacobRodrigues, Cassandra.ibarrac1, Das MiMaMi, César Krall, Ememe, Reisub, Alejandro Apolinar, Rodriguezcabanzo, Alejosu, Gaaplex, Jarould, Crystallizedcarbon, Pakwmdmmd, BenjaBot, 4lextintor, Keypyhh, Carlosqwerty, Manudark12, JMDartz, Ks-M9, Artur dmx, Jero1500, Africanito, Juanperezgarcialopez99, Hector SDuarez, Cpunto y Anónimos: 593 • JavaScript Fuente: https://es.wikipedia.org/wiki/JavaScript?oldid=90290977 Colaboradores: Andre Engels, Moriel, ManuelGR, Robbot, Sanbec, Zwobot, Comae, Dodo, Triku, Ascánder, Sms, Rsg, Tostadora, Murphy era un optimista, Aldodell, Atalatlae, Choan, Niqueco, Renabot, Boticario, RobotJcb, Airunp, JMPerez, Edub, Taichi, Rembiapo pohyiete (bot), RJacinto, Rufous~eswiki, Magister Mathematicae, Dem, Viko~eswiki, RobotQuistnix, Alhen, Superzerocool, Chobot, Arevaloce, Mazhack, Yrbot, DerkeNuke, Seanver, BOT-Superzerocool, FlaBot, Vitamine, BOTijo, YurikBot, Icvav, Zam, Beto29, KnightRider, The Photographer, Jesuja, Txo, Isra00, Maldoror, Hoblap, Haitike, Zanaqo, Siabef, Paintman, Jorgechp, Faelomx, Bufalo 1973, BOTpolicia, Ál, CEM-bot, Jota.ele.ene, Laura Fiorucci, Marc-André Aßbrock, Ignacio Icke, Especiales, Roberpl, Rosarinagazo, Antur, Thijs!bot, Jmacoe, Ñuño Martínez, JoaquinFerrero, Gotrek~eswiki, Locovich, Isha, Mpeinadopa, JAnDbot, Spa karmona, Rubelodi, Mansoncc, Jaime García Marsá, Don Depresor, Muro de Aguas, TXiKiBoT, Luis junco, Almohada2, ColdWind, Humberto, Willmont, Rei-bot, Fixertool, Behemot leviatan, Pedro Nonualco, Chabbot, Idioma-bot, Demimismo, Pólux, Snakefang, JMd, Biasoli, TottyBot, Bucephala, Calvia, Cinevoro, VolkovBot, Technopat, Queninosta, Matdrodes, Elabra sanchez, Mjcuevas, Synthebot, BlackBeast, Shooke, Lucien leGrey, Vatelys, Mytwm, Muro Bot, SieBot, PaintBot, Loveless, Macarrones, Carmin, Obelix83, Drinibot, Bigsus-bot, BOTarate, Tolitose, Inuyasha1111, Manwë, El bot de la dieta, Tirithel, Amischol, Jmmuguerza, HUB, Tosin2627, Eduardosalg, Botellín, Leonpolanco, Poco a poco, Osado, Efsandino, Camilo, UA31, Lockalbot, AVBOT, LucienBOT, MastiBot, MarcoAurelio, Ezarate, Enramos, Diegusjaimes, CarsracBot, Arjuno3, Luckas-bot, Nallimbot, Roinpa, FariBOT, Jotterbot, Bucle, AlexandroRR, SuperBraulio13, Ortisa, Manuelt15, Xqbot, Jkbw, Maximilianomilicich, Rubinbot, FrescoBot, Kismalac, Igna, Adryitan, Botarel, Amgc56, Piglesias, D'ohBot, TobeBot, Psylard, RedBot, Rameshngbot, Vubo, DixonDBot, Abece, Born2bgratis, Marjuanm, PatruBOT, JjedMoriAnktah, Alph Bot, KSEltar, Waeswaes, Jorge c2010, Foundling, EmausBot, Ojoavisor, Sergio Andres Segovia, Grillitus, JackieBot, Hoo man, Rubpe19, ChuispastonBot, Oxes, DRAKCMEZA, Movsesbot, Viferico, AStarBot, UAwiki, Invadibot, Cinet uv, Allan Aguilar, Conopo, Jr JL, Elvisor, Rauletemunoz, MaKiNeoH, Legobot, Makore2, Denisvacamonar, Coins, Timohap, Ineditable, Jarould, Matiia, BenjaBot, Luisgarciaweb, Sony Xperia Z, Gonzalo Rodriguez Zabala, Karem uttaleb, Sfr570, Ehhhmaincraa, Arcadiogarcia, Ne roll 10, Ks-M9, Peaceis4all y Anónimos: 427 • PHP Fuente: https://es.wikipedia.org/wiki/PHP?oldid=90385011 Colaboradores: Maveric149, Joseaperez, Sabbut, Moriel, Sauron, Jor-


128

CAPÍTULO 6. ORIGEN DEL TEXTO Y LAS IMÁGENES, COLABORADORES Y LICENCIAS

geGG, Pilaf, Lourdes Cardenal, ManuelGR, Julie, Nonick, Angus, Sanbec, Aparejador, Zwobot, Comae, Bermiego, Aloriel, TheBK, Interwiki, Drjackzon, Rosarino, Dodo, Ejmeza, Gmagno, Levhita, Triku, Ascánder, Sms, Cookie, Tostadora, Darklooker, Murphy era un optimista, Barcex, Jarfil, Sunsinron, Vicaram, Carlos I, Jecanre, Tarzanete, Cinabrium, Almorca, Fmariluis, Atomo64, Kerberos~eswiki, Txuspe, Desatonao, Niqueco, Pablete2005, Wikier~eswiki, LeonardoRob0t, Digigalos, Contractil, Hispa, Airunp, Edub, OMA, Rembiapo pohyiete (bot), Syrus, OMenda, Orgullobot~eswiki, Murven, RobotQuistnix, ERFon, Platonides, Unf, Alhen, Superzerocool, Chobot, Paradoja, Lefrato, Aeoris, Yrbot, Amadís, BOT-Superzerocool, FlaBot, RicardoCorai, Vitamine, Dangarcia, YurikBot, Mig21bp, Cameri, Gustavoang, Icvav, GermanX, Huds, Xombra, Equi, Jyon, Armin76, Yonderboy, KnightRider, The Photographer, YoaR, Delunahugoren, Gronky, No sé qué nick poner, Jesuja, FedericoMP, Txo, Seretbit, Humanware, Nakayama~eswiki, Ernesto Graf, Gnovaro, Isra00, Kepler Oort, Maldoror, Mogutu, Er Komandante, Estemon, Leonardocaballero, Tomatejc, Zanaqo, Jarke, Siabef, Covi, Boja, Niuweme, LuisManson, Faelomx, Lance~eswiki, Edegugli, Bernethe, Jstitch, BOTpolicia, Tonibilly, Qwertyytrewqqwerty, Judas iscariote, Xobra, Hawking, CEM-bot, Meltryth, Gabriel Acquistapace, Maniaticko, Marc-André Aßbrock, -jem-, Alexav8, Ignacio Icke, Rickware, NickelSpider, Baiji, Ugur Basak Bot~eswiki, Exos, Santhy, Mister, Rastrojo, Jolumo.ar, AndreX, Montgomery, FrancoGG, Manz, Resped, Thijs!bot, Sitiosmdq, Rocandante, VARGUX, Mahadeva, Eloi.sanmartin, Neo139, Ing amc, Yeza, Pabbec, RoyFocker, JoaquinFerrero, Gotrek~eswiki, Wikispanishuser, Josemanuelgp, Locovich, Botones, Cratón, Isha, Xoneca, MetalMind, Vitorres, JAnDbot, Spa karmona, JuanRodríguez, Kved, Ingolll, Shakaran, Mansoncc, Hvallenilla, Muro de Aguas, Gsrdzl, Reinam, Walterllanos, TXiKiBoT, Wpersei, Zenkor, Gustronico, Der metzgermeister, ColdWind, Gacq, Humberto, Netito777, Sagues, Rei-bot, Agarzon, Bedwyr, Chabbot, Idioma-bot, Pólux, Biasoli, Danielstp, Bucephala, Calvia, AlnoktaBOT, Dusan, Cinevoro, VolkovBot, Snakeyes, Jose figueredo, Galandil, Raystorm, Xiul, Darkxnightmare, Matdrodes, DJ Nietzsche, Shooke, JMorchio, Barri, Patio~eswiki, AlleborgoBot, Amitie 10g, Muro Bot, Globalpegasus, Numbo3, Racso, Mjollnir1984, SieBot, Danielba894, Alvk4r, Loveless, Obelix83, Cobalttempest, Vladimirjimenez, EdmenBot, Bigsus-bot, Dark, BOTarate, Manwë, Ugly, Atilathehun, Ashrey, Tirithel, Locos epraix, Jarisleif, Javierito92, HUB, Cocojeison, Minterior, Pare Mo, Pumk, PixelBot, Tosin2627, Leonpolanco, Pan con queso, Poco a poco, Franj4, Alexbot, Nowarco, Darkicebot, Paporrubio, PhoneixS, Raulshc, Mike.lifeguard, Osado, Purbo T, Fragale, Camilo, UA31, Manuel-f-3, Holothurion, Manvehe, AVBOT, MastiBot, Vituzzu, Miguelzilli, Diegusjaimes, MelancholieBot, Arjuno3, Andreasmperu, Luckas-bot, Nallimbot, FariBOT, Jotterbot, Vic Fede, Ynnek, Djrolando, Gacpro, Cabseiya, AlexFBP, Hampcky, Pausalvi, Nixón, ErizoAzul, ArthurBot, Viriato22, Phansys, SuperBraulio13, Ikarush, Manuelt15, Xqbot, Jkbw, Worvast, KAziKE81, Rafucho12, NixBot, Javier.eguiluz, Erkow, Igna, Torrente, Adryitan, Botarel, Labina7, Betomorales, TiriBOT, MondalorBot, Jakeukalane, Frutero, TeLiX, Jcfidy, TobeBot, Vennersteve, Caritdf, RedBot, Joanfont, Kizar, Acifuentes, Josexu32, Bunchosia, El mago de la Wiki, Pownerus, Jembot, PatruBOT, KamikazeBot, Kenichiaeb, Dantrix2006, Tarawa1943, Biktora, Walturius, Migke, Jorge c2010, SamuraiBot~eswiki, Csalrais, JorgeVla, EmausBot, Victor fidel serrano, Neoyukito, Savh, AVIADOR, ZéroBot, Alexrr1195, ChessBOT, Ceorcham, TuHan-Bot, 1v4n X, J. A. Gélvez, Bmolina~eswiki, Grillitus, TerryFish, Sgmendez, MartinAraujo, Emiduronte, MadriCR, Waka Waka, Frigotoni, Razican, Dussarax, SaeedVilla, MerlIwBot, Tecnocat128, Rolfrid, MetroBot, Invadibot, HiW-Bot, KshanaRules, EduMurru, Conopo, Nicoliky, Mechita korn, Elvisor, CanaryESP, Reok, Flashlack, Omanriquez, Syum90, MaKiNeoH, Solarstone, SantoBOT, Addbot, Balles2601, ScotXW, MarcoDgz, DaniBarca, Programu, Jarould, Egis57, BenjaBot, OsmaK, JuanCalamidad, Gonzalo Rodriguez Zabala, Aldepo, Antotg, ROLEX Front Running on Long Island, Hebbx y Anónimos: 766 • Visual Basic Fuente: https://es.wikipedia.org/wiki/Visual_Basic?oldid=90587832 Colaboradores: Pablo.cl, Pilaf, Angus, Comae, Tony Rotondas, Dodo, Ricpelo, Jynus, Ascánder, Sms, Rsg, Cookie, Murphy era un optimista, PeiT, Dianai, Fenririel, Cinabrium, Porao, Schummy, Loco085, Renabot, Boticario, Zeioth, Deleatur, Soulreaper, Petronas, Orgullomoore, Hispa, Edub, Taichi, Patricio.lorente, Rembiapo pohyiete (bot), Zohar~eswiki, Magister Mathematicae, Luismiad, RobotQuistnix, Platonides, Alhen, Superzerocool, Chobot, Yrbot, Baifito, FlaBot, Vitamine, BOTijo, YurikBot, Mortadelo2005, Gaeddal, GermanX, KnightRider, Dweigel, No sé qué nick poner, Jesuja, FedericoMP, Gustavo.ovalle, Sodaxp, Banfield, Jlboya, Bcoto, Er Komandante, Lasneyx, Chlewbot, Tomatejc, Filipo, Axxgreazz, Jorgechp, Nocker, Cad, Kn, BOTpolicia, Takachan, CEM-bot, Laura Fiorucci, Tripy, Asegim77, -jem-, Chabacano, Dalmiant, X.Cyclop, Durero, Especiales, Retama, Baiji, Pacovila, Eamezaga, Antur, CF, Montgomery, Thijs!bot, Logongas, Un Mercenario, Cansado, Sobreira, Mahadeva, Ñuño Martínez, Yeza, RoyFocker, Bryant1410, Botones, Isha, Kenbill, Gusgus, Jurgens~eswiki, Jugones55, Y0rx, Miguelo on the road, Cmontero, 4aDimension, VanKleinen, Kved, Pmisiones, Mansoncc, Diego Godoy, CommonsDelinker, TXiKiBoT, Bboccioz, Sergiosh, ColdWind, Gacq, Elisardojm, Humberto, Netito777, Lecturalia, Lex Sparrow, Bedwyr, Pólux, Galaxy4, Snakefang, Fcr, Manuel Trujillo Berges, Biasoli, Seykron, Bucephala, Fremen, Cinevoro, VolkovBot, Snakeyes, Technopat, C'est moi, Penelopina, Galandil, Matdrodes, Fernando Estel, Carcediano, BlackBeast, Shooke, Lucien leGrey, AlleborgoBot, 3coma14, Edmenb, YonaBot, SieBot, Jogacrack, Obelix83, Cobalttempest, Jacina~eswiki, Luis ademir, Drinibot, Dark, BOTarate, Pelutnik, JJLR, Manwë, Ugly, Greek, BuenaGente, Aleposta, Mafores, Tirithel, Locos epraix, XalD, Jarisleif, Javierito92, Marcecoro, Nicolasdavel, HUB, MetsBot~eswiki, Nicop, Eduardosalg, Veon, Qwertymith, Leonpolanco, Pan con queso, GLuky, ººGaRvAºº, Alejandrocaro35, Poco a poco, Sidcc, Danathor, Antonio Irazabal, Açipni-Lovrij, Norberto Perez G., SilvonenBot, UA31, SergioN, AVBOT, David0811, MarcoAurelio, Ezarate, Diegusjaimes, DumZiBoT, MelancholieBot, Innv, Arjuno3, InflaBOT, Error de inicio de sesión, Andreasmperu, Luckas-bot, Mrchuseau, Uswikisa, Rafael1193, Jotterbot, Vic Fede, Dangelin5, Jorge 2701, Markoszarrate, La concha de tu hermana 22, Barteik, Billinghurst, Mara 95, Briancarloscondenanza, Sakhal~eswiki, ArthurBot, Argentinoo, Emmanuele, SuperBraulio13, Ortisa, Elamericanono, Manuelt15, Xqbot, Jkbw, SassoBot, Dreitmen, Jaimemf, Bitarray, Metronomo, Nachojr99, Igna, Lraingele, Torrente, Botarel, SantiBadia, 987654321ajs, BOTirithel, Hprmedina, Halfdrag, RedBot, Marsal20, Hubert Stiven, Abece, Carlos tenorio ortega, PatruBOT, Angelito7, Nicoobe, Humbefa, Tolo Cunill, TheXDS, Fsalas4000, Edslov, EmausBot, Savh, AVIADOR, Sergio Andres Segovia, Rubpe19, MercurioMT, WikitanvirBot, Diamondland, Antonorsi, Travelour, Invadibot, Doublebassjihh, LlamaAl, Tajampi, Elvisor, Helmy oved, SAulVillalobos, Flashlack, RomanLier, Syum90, Addbot, Marcrodos, Giliofelix, Laberinto16, GOFURSELF, César Krall, Jarould, Matiia, Egis57, Jose Ciprian III, Fernando2812l, Ks-M9, Miranda moedano nestor Fernando, DavidXDAT y Anónimos: 691 • Python Fuente: https://es.wikipedia.org/wiki/Python?oldid=90527880 Colaboradores: AstroNomo, Maveric149, Macar~eswiki, Changux, Fibonacci, Moriel, Frutoseco, Sauron, Pilaf, Robbot, Juan Manuel, Sanbec, Riviera, Tony Rotondas, Dodo, Levhita, Ascánder, Sms, Tostadora, Elwikipedista, Tano4595, Salu2, Tin nqn, Jarfil, Robotito, Wolfete, JavierCantero, Mandramas, Ikks, NeV3rKilL, Cinabrium, Porao, Almorca, Fmariluis, Renabot, FAR, Cybedu, Ark~eswiki, RobotJcb, Hari Seldon, Emijrp, Patricio.lorente, Rembiapo pohyiete (bot), Tico~eswiki, Genba, Andreums, Sbassi, Dem, Kokoo, Orgullobot~eswiki, RobotQuistnix, Unf, Superzerocool, Chobot, Dibujon, Yrbot, FlaBot, Varano, Vitamine, BOTijo, YurikBot, GermanX, Willtron, Indu~eswiki, YoaR, Gronky, Eloy, Crisneda2000, Garthof, Kepler Oort, Leonardocaballero, Shevek~eswiki, PODA, Qwertyytrewqqwerty, CEM-bot, Daniel De Leon Martinez, Alexav8, Durero, Especiales, Retama, Carlos Pino, Osepu, Anonimato1990, Rastrojo, Rosarinagazo, Ggenellina, Thijs!bot, PabloCastellano, Javierrami, Jileon, RoyFocker, Bryant1410, JoaquinFerrero, AntBiel, Ninovolador, Karlhangas, Isha, Atardecere, Chuck es dios, Vitorres, Rar~eswiki, JAnDbot, LogC, Diego4serve, Kved, Lucianobrom, BetBot~eswiki, Muro de Aguas, PointToNull, Abalastegui, CommonsDelinker, TXiKiBoT, Edorka, Muimota, Sardanapalus, Rei-bot, NaSz, Fixertool, Alecu~eswiki, Chabbot, Galaxy4, Manuel Trujillo Berges, Biasoli, Jcea, AlnoktaBOT, Dusan, Cinevoro, VolkovBot, Jiptohej, George.bo, Matdrodes, Synthebot, Shooke, Lucien leGrey, Chassoul, Ricardo 369, Blenderation, Muro Bot, Fran4004, Radical88, Dura-Ace, SieBot, Igneus~eswiki, Loveless, Tucapl, Obelix83, Cobalttempest,


6.2. IMÁGENES

129

Drinibot, BOTarate, Tolitose, Jlenton, Greek, Yonseca, Tirithel, Javi1977, Dnu72, Piero71, Nicop, Tosin2627, Leonpolanco, Botito777, LordT, Walter closser, CestBOT, Lluvia, Misigon, MastiBot, Diegusjaimes, DumZiBoT, Arcangelsombra, Trimax, Raulisea, Vigesimo, Madalberta, Ptbotgourou, FariBOT, Jotterbot, Cplusplus~eswiki, PuercoPop, Marxto, ArthurBot, Wikijandro, Jrarias2005, Ortisa, Xqbot, Jkbw, SassoBot, Surfaz, At93, Adryitan, Botarel, Leek~eswiki, AstaBOTh15, WLoku, Hprmedina, TobeBot, RedBot, Teknad, Edgardo C, PatruBOT, Ganímedes, Nessa los, Machipremier, Alph Bot, Felga16, Tarawa1943, JuanGoldenboy, Nekmo, EmausBot, HRoestBot, Sergio Andres Segovia, Jcaraballo, Mentibot, ChuispastonBot, WikitanvirBot, Patrias, Poeta3d, Ala lee, Aandresortiz, MerlIwBot, UAwiki, MetroBot, Invadibot, Conopo, Nernix1, Bibliofilotranstornado, Archimagow, Metalzonix, Jorg Ag, Jr JL, Syrusakbary, Elvisor, Asqueladd, Helmy oved, Takumi 1, Flashlack, Round Em, Maucendon, EduLeo, Tgor, Legobot, Txasatonga, Benjapunk69, Puntoinfinito, Addbot, FrancoCorrea, ScotXW, Patronus1990, Serafin88, Manusoftar, Patrios, Joserrientos, Jarould, BenjaBot, Mrm40s, Gonzalo Rodriguez Zabala, Ernestcairo, 123neomar, Blueberto, AdamPro, Jjl 0891 y Anónimos: 273 • Lenguaje ensamblador Fuente: https://es.wikipedia.org/wiki/Lenguaje_ensamblador?oldid=90416467 Colaboradores: Sabbut, Moriel, JorgeGG, Pilaf, ManuelGR, Robbot, Sanbec, Triku, Jynus, Sms, Robotito, Bgbot, Porao, Darz Mol, Vizcarra~eswiki, Z80user, MatiasBellone, Richy, Digigalos, Boticario, AlfonsoERomero, Airunp, Emijrp, RobotQuistnix, Platonides, Chobot, Yrbot, Vitamine, GermanX, Beto29, Gothmog, Jesuja, Santiperez, Maldoror, Tomatejc, BOTpolicia, Qwertyytrewqqwerty, CEM-bot, Jorgelrm, Laura Fiorucci, X.Cyclop, ^CiViLoN^, Psicodelico6, Antur, FrancoGG, Thijs!bot, Roberto Fiadone, JoaquinFerrero, Locovich, Isha, JAnDbot, Jugones55, Kved, Segedano, Rafa3040, Muro de Aguas, TXiKiBoT, Oespinosa, Netito777, Marvelshine, Biasoli, VolkovBot, Technopat, Galandil, Matdrodes, Elabra sanchez, House, Erickmr, Barri, Muro Bot, BotMultichill, SieBot, Loveless, Drinibot, BOTarate, Manwë, Correogsk, El bot de la dieta, BuenaGente, Mrisco, DorganBot, Tirithel, Piero71, Lentucky, Botellín, CestBOT, Valentin estevanez navarro, Kroji, AVBOT, LucienBOT, Tanhabot, NjardarBot, Gades21, Diegusjaimes, Hann~eswiki, Innv, Saloca, Andreasmperu, Luckas-bot, Lu Tup, Kbradero, SuperBraulio13, Xqbot, Jkbw, Ricardogpn, Albertochoa, Surfaz, Botarel, AstaBOTh15, TiriBOT, Scapegoat001, Jcfidy, Halfdrag, Kizar, Codename, Jerowiki, PatruBOT, Dinamik-bot, GrouchoBot, G Garro, EmausBot, Sergio Andres Segovia, Grillitus, WikitanvirBot, R010178, ILoveSugar, ChayitaBOT, Mane2517, Elvisor, DanielithoMoya, AlbertoCamilo, Addbot, Carlos7755, MarioFinale, Jarould, BenjaBot, HannaTheKitty12, Fernando2812l, Ks-M9, Labashi-Marduk, FrancoCaviglia y Anónimos: 173 • Algoritmo Fuente: https://es.wikipedia.org/wiki/Algoritmo?oldid=90553497 Colaboradores: Llull~eswiki, Pit~eswiki, Sabbut, Moriel, Sauron, JorgeGG, Lourdes Cardenal, ManuelGR, Julie, Angus, Vivero, Riviera, Rosarino, Dodo, Ejmeza, Crescent Moon, Triku, Sms, Rsg, Tostadora, Elwikipedista, Tano4595, Jsanchezes, Ríos-Ortega, JAAC, Jecanre, Cinabrium, Schummy, Huhsunqu, Balderai, Ecemaml, Renabot, FAR, Ictlogist, Boticario, Soulreaper, Orgullomoore, AlfonsoERomero, Airunp, JMPerez, Edub, Yrithinnd, Taichi, Emijrp, Rembiapo pohyiete (bot), Caiser, Magister Mathematicae, RobotQuistnix, Alhen, Superzerocool, Chobot, Dromero, Sancebau, Yrbot, Amadís, FlaBot, Vitamine, .Sergio, YurikBot, Mortadelo2005, GermanX, Zam, Willtron, KnightRider, The Photographer, YoaR, Gothmog, No sé qué nick poner, Carutsu, C-3POrao, Jesuja, Banfield, Kepler Oort, Maldoror, Er Komandante, Camima, Haitike, KocjoBot~eswiki, Tomatejc, Jarke, Paintman, Rbonvall, Kn, Aleator, Jstitch, BOTpolicia, Gizmo II, CEM-bot, Jorgeu, Jorgelrm, Laura Fiorucci, Kojie, -jem-, Alexav8, Ignacio Icke, Efegé, Retama, AlphaWiki~eswiki, Baiji, Bot~eswiki, Antur, Dorieo, Ingenioso Hidalgo, Fsd141, AlbertMA, Thijs!bot, Xxim, Alvaro qc, Escarbot, Yeza, Zupez zeta, Drake 81, RoyFocker, Ninovolador, MorZilla, Cratón, Isha, Dogor, Gusgus, Obueno, JAnDbot, Jugones55, JuanRodríguez, Kved, DerHexer, Lecuona, Mansoncc, Muro de Aguas, Xavigivax, TXiKiBoT, S3v3r-1, Elisardojm, Humberto, Netito777, Sophie kowalsky, AS990, ZrzlKing, Chabbot, Pólux, Bucephala, AchedDamiman, VolkovBot, Snakeyes, Technopat, Queninosta, Raystorm, Libertad y Saber, Matdrodes, Elabra sanchez, Synthebot, DJ Nietzsche, BlackBeast, Shooke, AlleborgoBot, Muro Bot, Peregring-lk, Clarad, Komputisto, MiguelAngel fotografo, SieBot, Aitorzubiaurre, Danielba894, Ctrl Z, Francisco Mochis, Carmin, Rigenea, Drinibot, CASF, BOTarate, Arlm1, Fide07, STBot~eswiki, Mel 23, Guillervf91, Manwë, Fegc77, Greek, H3r3dia, BuenaGente, Qix~eswiki, Relleu, PipepBot, Fadesga, Chuchot, Tirithel, Mutari, XalD, robot, Jarisleif, Javierito92, HUB, PeruProfe, Farisori, McMalamute, Estirabot, Eduardosalg, Veon, Leonpolanco, Pan con queso, Mar del Sur, Alejandrocaro35, Botito777, Petruss, Alexbot, Darkicebot, Valentin estevanez navarro, RoyFokker, Raulshc, Açipni-Lovrij, SilvonenBot, Camilo, UA31, Ucevista, AVBOT, David0811, Flakinho, Nocturnogatuno, MastiBot, Pedrito suarez, Angel GN, MarcoAurelio, Speedplus, Ezarate, Diegusjaimes, Jjflorescueto, Arjuno3, Andreasmperu, Luckas-bot, Virgi, Ptbotgourou, Jotterbot, Vic Fede, Dangelin5, Eduman~eswiki, Nixón, DSisyphBot, XZeroBot, ArthurBot, RadiX, Lcpousa, SuperBraulio13, M.heda, Xqbot, Jkbw, GhalyBot, Junior1209, Pedrovicenterosero, Calitb, Dan6hell66, Ricardogpn, Albertochoa, Igna, Torrente, Botarel, BenzolBot, Rexmania, Heynry1, Gusbelluwiki, Jhoelito14, TobeBot, Adrianantoniors, Imperioonepiece, Halfdrag, Aquiel, Mipataentutrasero, Wikielwikingo, Hantartico, KamikazeBot, , Abel406, TjBot, Alph Bot, Humbefa, Irvinopuma, Tarawa1943, Carlo el calvo, Shining.Star, Foundling, GrouchoBot, Xxxmagicmanxxx, Edslov, EmausBot, Savh, HRoestBot, Sergio Andres Segovia, Macrocoliset, Emiduronte, ChuispastonBot, MadriCR, Waka Waka, Xpress500, Mjbmrbot, Miguel hdez, Ksarasola, Palissy, Metrónomo, Antonorsi, MerlIwBot, Papaplus, Renly, ClausxD, Arthur 'Two Sheds’ Jackson, Sebrev, Ginés90, Kotas, MetroBot, Henry bedon, Gusama Romero, Acratta, Metilisopropilisergamida, Vetranio, Elvisor, Sandovaltk10, DanielithoMoya, Helmy oved, Syum90, Javifields, Legobot, Eyetheunlord, Balles2601, ConnieGB, Angelrafa00, SuZumiya, Jarould, Matiia, Egis57, Crystallizedcarbon, AlvaroMolina, AlexGaitan, Deforetop6, Yholo, Andres477, Sapristi1000, CarlosAR2000, Benito Álvaro Cifuentes, Lalito312000, Benigno Jimenez Garay, Lectorina, Holaxddddd, MatiasOlivera0, Joltenick, Ks-M9, Jesu2000s, Gemamorbar, A1ejandro2000 y Anónimos: 861 • Estructura de datos Fuente: https://es.wikipedia.org/wiki/Estructura_de_datos?oldid=90004686 Colaboradores: Edulix, Soniautn, Sabbut, Moriel, Sauron, Julie, Zwobot, Comae, Dodo, Triku, Fortran~eswiki, Ascánder, Sms, Rsg, Murphy era un optimista, Jsanchezes, LPR, Porao, Alexan, Emijrp, Rembiapo pohyiete (bot), RobotQuistnix, Platonides, Chobot, Yrbot, BOTijo, YurikBot, Icvav, KnightRider, Jesuja, Txo, Götz, Maldoror, Chlewbot, Tomatejc, Fercufer, Laura Fiorucci, Alexav8, Fsd141, Thijs!bot, Juan25, Rasilga, Miguelo on the road, TXiKiBoT, Juan renombrado, Hidoy kukyo, Danthux, Humberto, Developer, Biasoli, AlnoktaBOT, VolkovBot, Matdrodes, YonaBot, BotMultichill, SieBot, Loveless, Correogsk, Leonpolanco, Furti, Alexbot, Açipni-Lovrij, SilvonenBot, Rrupo, AVBOT, David0811, MastiBot, MarcoAurelio, Diegusjaimes, DumZiBoT, Luckas-bot, Yonidebot, ArthurBot, Alexandravargas, SuperBraulio13, Ortisa, Xqbot, Jkbw, Asfarer, FrescoBot, Ricardogpn, Botarel, Aquiel, PatruBOT, Dinamik-bot, Crg 85, EmausBot, ZéroBot, WikitanvirBot, Manubot, Xerox 5B, Rezabot, MerlIwBot, Jetjanoli, V.aguado, Seasz, Addbot, DarkBlueZV, Jarould, Ks-M9 y Anónimos: 91

6.2 Imágenes • Archivo:AlgoritmoRaiz.png Fuente: https://upload.wikimedia.org/wikipedia/commons/2/26/AlgoritmoRaiz.png Licencia: CC-BY-SA3.0 Colaboradores: Trabajo propio, hecho con OpenOffice.org Draw Artista original: Kn • Archivo:BjarneStroustrup.jpg Fuente: https://upload.wikimedia.org/wikipedia/commons/d/da/BjarneStroustrup.jpg Licencia: GFDL Colaboradores: Bjarne Stroustrup’s homepage Artista original: ?


130

CAPÍTULO 6. ORIGEN DEL TEXTO Y LAS IMÁGENES, COLABORADORES Y LICENCIAS

• Archivo:C_plus_plus.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/5/5b/C_plus_plus.svg Licencia: Public domain Colaboradores: Trabajo propio Artista original: JTojnar • Archivo:Check_mark.png Fuente: https://upload.wikimedia.org/wikipedia/commons/f/f0/Check_mark.png Licencia: CC BY-SA 3.0 Colaboradores: Wikipedia Artista original: Wikipedia • Archivo:Classes_and_Methods.png Fuente: https://upload.wikimedia.org/wikipedia/commons/d/d0/Classes_and_Methods.png Licencia: CC BY-SA 3.0 Colaboradores: Using SublimeText Artista original: Bobbygammill • Archivo:CodeCmmt002.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/7/75/CodeCmmt002.svg Licencia: CC BY 2.5 Colaboradores: Transferido desde en.wikipedia a Commons.28041964 Artista original: The original uploader was Dreftymac de Wikipedia en inglés • Archivo:Codigo_de_maquina.png Fuente: https://upload.wikimedia.org/wikipedia/commons/f/f3/Codigo_de_maquina.png Licencia: Public domain Colaboradores: Trabajo propio Artista original: German • Archivo:Commons-emblem-copyedit.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/e/e8/Commons-emblem-copyedit. svg Licencia: CC BY-SA 3.0 Colaboradores: • File:Gnome-emblem-important.svg Artista original: GNOME icon artists, Fitoschido • Archivo:Commons-emblem-question_book_orange.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/1/1f/Commons-emblem-question_ book_orange.svg Licencia: CC BY-SA 3.0 Colaboradores: <a href='//commons.wikimedia.org/wiki/File:Commons-emblem-issue.svg' class='image'><img alt='Commons-emblem-issue.svg' src='https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Commons-emblem-issue. svg/25px-Commons-emblem-issue.svg.png' width='25' height='25' srcset='https://upload.wikimedia.org/wikipedia/commons/thumb/b/ bc/Commons-emblem-issue.svg/38px-Commons-emblem-issue.svg.png 1.5x, https://upload.wikimedia.org/wikipedia/commons/thumb/ b/bc/Commons-emblem-issue.svg/50px-Commons-emblem-issue.svg.png 2x' data-file-width='48' data-file-height='48' /></a> + <a href='//commons. wikimedia.org/wiki/File:Question_book.svg' class='image'><img alt='Question book.svg' src='https://upload.wikimedia.org/wikipedia/ commons/thumb/9/97/Question_book.svg/25px-Question_book.svg.png' width='25' height='20' srcset='https://upload.wikimedia.org/wikipedia/ commons/thumb/9/97/Question_book.svg/38px-Question_book.svg.png 1.5x, https://upload.wikimedia.org/wikipedia/commons/thumb/ 9/97/Question_book.svg/50px-Question_book.svg.png 2x' data-file-width='252' data-file-height='199' /></a> Artista original: GNOME icon artists, Jorge 2701 • Archivo:Commons-emblem-scales.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/c/c6/Commons-emblem-scales.svg Licencia: GPL Colaboradores: File:Commons-emblem-issue.svg and File:Emblem-scales.svg Artista original: Derived work: User:Srhat Source files: • Archivo:Commons-logo.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/4/4a/Commons-logo.svg Licencia: Public domain Colaboradores: This version created by Pumbaa, using a proper partial circle and SVG geometry features. (Former versions used to be slightly warped.) Artista original: SVG version was created by User:Grunt and cleaned up by 3247, based on the earlier PNG version, created by Reidab. • Archivo:EsquemáticaAlgoritmo1.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/a/a3/Esquem%C3%A1ticaAlgoritmo1. svg Licencia: GFDL Colaboradores: Trabajo propio Artista original: Kn • Archivo:FortranCardPROJ039.agr.jpg Fuente: https://upload.wikimedia.org/wikipedia/commons/5/58/FortranCardPROJ039.agr.jpg Licencia: CC BY-SA 2.5 Colaboradores: I took this picture of an artifact in my possession. The card was created in the late 1960s or early 1970s and has no copyright notice. Artista original: Arnold Reinhold • Archivo:Guido_van_Rossum_OSCON_2006.jpg Fuente: https://upload.wikimedia.org/wikipedia/commons/6/66/Guido_van_Rossum_ OSCON_2006.jpg Licencia: CC BY-SA 2.0 Colaboradores: 2006oscon_203.JPG Artista original: Doc Searls • Archivo:Hash_table_es.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/1/19/Hash_table_es.svg Licencia: CC BY-SA 4.0 Colaboradores: Trabajo propio Artista original: Ascánder • Archivo:Heckert_GNU_white.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/2/22/Heckert_GNU_white.svg Licencia: CC BY-SA 2.0 Colaboradores: gnu.org Artista original: Aurelio A. Heckert <aurium@gmail.com> • Archivo:LAMP_software_bundle.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/8/82/LAMP_software_bundle.svg Licencia: CC BY-SA 3.0 Colaboradores: Esta imagen incluye elementos que han sido tomados o adaptados de esta: <a href='//commons. wikimedia.org/wiki/File:Tux-shaded.svg' class='image'><img alt='Tux-shaded.svg' src='https://upload.wikimedia.org/wikipedia/commons/ thumb/0/0a/Tux-shaded.svg/17px-Tux-shaded.svg.png' width='17' height='20' srcset='https://upload.wikimedia.org/wikipedia/commons/ thumb/0/0a/Tux-shaded.svg/25px-Tux-shaded.svg.png 1.5x, https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Tux-shaded. svg/33px-Tux-shaded.svg.png 2x' data-file-width='249' data-file-height='297' /></a> Tux-shaded.svg. Artista original: ScotXW • Archivo:LampFlowchart-es.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/b/bd/LampFlowchart-es.svg Licencia: CC BY-SA 3.0 Colaboradores: • LampFlowchart.svg Artista original: LampFlowchart.svg: svg by Booyabazooka • Archivo:Nuvola_apps_konsole.png Fuente: https://upload.wikimedia.org/wikipedia/commons/2/24/Nuvola_apps_konsole.png Licencia: LGPL Colaboradores: http://icon-king.com Artista original: David Vignoni / ICON KING • Archivo:PET-basic.png Fuente: https://upload.wikimedia.org/wikipedia/commons/0/0b/PET-basic.png Licencia: Public domain Colaboradores: Trabajo propio Artista original: Rafax • Archivo:PHP-logo.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/2/27/PHP-logo.svg Licencia: Public domain Colaboradores: ? Artista original: ? • Archivo:Pair_Programming.jpg Fuente: https://upload.wikimedia.org/wikipedia/commons/6/66/Pair_Programming.jpg Licencia: CC BY-SA 3.0 Colaboradores: Trabajo propio Artista original: Calqui • Archivo:Pauscal_lenguaje_de_programación.png Fuente: https://upload.wikimedia.org/wikipedia/commons/3/32/Pauscal_lenguaje_ de_programaci%C3%B3n.png Licencia: CC BY-SA 4.0 Colaboradores: Trabajo propio Artista original: DarkBlueZV • Archivo:Programming_language_textbooks.jpg Fuente: https://upload.wikimedia.org/wikipedia/commons/a/a0/Programming_language_ textbooks.jpg Licencia: Public domain Colaboradores: Trabajo propio Artista original: User:K.lee


6.3. LICENCIA DEL CONTENIDO

131

• Archivo:Python-logo-notext.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg Licencia: GPL Colaboradores: www.python.org Artista original: www.python.org • Archivo:Python_add5_syntax.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/e/e1/Python_add5_syntax.svg Licencia: Copyrighted free use Colaboradores: http://en.wikipedia.org/wiki/Image:Python_add5_syntax.png Artista original: Xander89 • Archivo:Python_batteries_included.jpg Fuente: https://upload.wikimedia.org/wikipedia/commons/6/68/Python_batteries_included. jpg Licencia: Attribution Colaboradores: https://www.python.org/images/batteries-included.jpg Artista original: Frank Stajano • Archivo:Spanish_Wikiquote.SVG Fuente: https://upload.wikimedia.org/wikipedia/commons/1/13/Spanish_Wikiquote.SVG Licencia: CC BY-SA 3.0 Colaboradores: derived from Wikiquote-logo.svg Artista original: James.mcd.nz • Archivo:Subprograma.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/9/98/Subprograma.svg Licencia: GFDL Colaboradores: Trabajo propio Artista original: Josell7 • Archivo:Translation_arrow.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/2/2a/Translation_arrow.svg Licencia: CCBY-SA-3.0 Colaboradores: gráfico vectorial con Inkscape Artista original: Jesse Burgheimer • Archivo:Wave.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/4/40/Wave.svg Licencia: BSD Colaboradores: http://duke. kenai.com/wave/index.html (new), https://duke.dev.java.net/images/wave/index.html (old) Artista original: sbmehta converted to SVG from Sun Microsystems AI version. • Archivo:Wikibooks-logo.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/f/fa/Wikibooks-logo.svg Licencia: CC BY-SA 3.0 Colaboradores: Trabajo propio Artista original: User:Bastique, User:Ramac et al. • Archivo:Wikiversity-logo-Snorky.svg Fuente: https://upload.wikimedia.org/wikipedia/commons/1/1b/Wikiversity-logo-en.svg Licencia: CC BY-SA 3.0 Colaboradores: Trabajo propio Artista original: Snorky • Archivo:Wiktionary-logo-es.png Fuente: https://upload.wikimedia.org/wikipedia/commons/0/06/Wiktionary-logo-es.png Licencia: CC BY-SA 3.0 Colaboradores: originally uploaded there by author, self-made by author Artista original: es:Usuario:Pybalo

6.3 Licencia del contenido • Creative Commons Attribution-Share Alike 3.0


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.