Ésta es la versión G o o g l e guardada en el caché de la http://wiki.lugmen.org.ar/twiki/view/Main/TyphonLanguage obtenida el 28 Ago 2005 07:43:43 GMT.
La caché de G o o g l e es la instantánea de la página que tomamos cuando exploramos la Web en forma automática.
Es posible que la página haya cambiado desde entonces. Haga clic aquí para ver la página actual sin resaltar.
Esta página guardada en el caché puede hacer referencia a imágenes que ya no están disponibles. Haga clic aquí para obtener únicamente el texto guardado en el caché. Para vincularse a esta página o para marcarla, utilice el siguiente url: http://www.google.com/search?q=cache:UudIjxQfm7IJ:wiki.lugmen.org.ar/twiki/view/Main/TyphonLanguage+typhonlanguage&hl=es
Google no tiene relación con los autores de esta página ni es responsable de su contenido. |
Se han resaltado estos términos de búsqueda: | typhonlanguage |
|
|
TyphonLanguage < Main < TWiki
%HTTP_EQUIV_ON_VIEW%
Contenidos
Qué es Typhon?
Typhon es (o será) un lenguaje de programación basado en C++ y Python.
Typhon tendrá sintaxis al estilo Python y será traducido a C++ de forma lo
más directa posible.
Por qué C++?
Porque es un lenguaje compilado eficiente y estándar, que provee una biblioteca
lo suficientemente completa como para no necesitar mucho más para escribir
cualquier programa. Porque dicha biblioteca estándar define ''interfaces'' que,
a pesar de no tener soporte en el lenguaje (por eso surge Typhon también), hace
que puedan usarse de forma consistente. Porque es extremadamente flexible y
poderoso, porque es compatible con C, con todo lo que eso significa (que no es
para nada poco).
Bueno, de más está decir que hacer un lenguaje compilado nuevo (sin traducirlo a
alguno existente) no sólo es un trabajo excesivamente monstruoso y para el cual,
al menos yo (luca) no estoy capacitado, sino que sería un reinventar un poco la
rueda.
Por qué Python?
Python es uno de los mejores lenguajes de alto nivel y su sintaxis simple
y clara es una de las principales razones. Python se puede leer de una forma
muy natural y aún así, no es para nada tedioso de escribir, de hecho es uno
de los lenguajes que más rápido puede tipearse. Python además obliga a
producir código legible, al hacer checheo de identación, otra característica
bastante deseable.
Por último, Python y C++ son parecidos en cuanto a las características que ofrecen,
al menos son los únicos 2 lenguajes que conozco que soportan herencia múltiple,
por ejemplo.
Qué significa Typhon
Luca un día se despertó cruzado (creo que después de alguna discusión sobre Mono
con gazer :) y se preguntó por qué catso no hay ningún lenguaje compilado de
relativo alto nivel. Entre otras cosas estuvo jugando con Pyrex (un lenguaje
python-like para hacer wrappers de C para Python); entre idas y venidas, se
pensó en hacer que Python se traduzca a una serie de clases predefinidas y usar
conteo de referencias para el manejo de memoria, etc; todo como para poder compilar
Python casi igual a como lo conocemos ahora traduciéndolo a C++. Entre esas ideas,
en algún momento alberto dijo "Python con tipos" y de ahí pensé en Typed Python y
vi la T y la Y muy cerca y pensé que empezando con Ty (de Typed) podría armar un
anagrama de Python. Lo obvio resultó Typhon.
Luego investigando el nombre, Typhon resulta ser una criatura de la
mitología griega
(un hombre/dragon con mil cabezas) al igual que Python (una especie de serpiente
gigante); pero hay más aún.
Tanto Typhon como Python fueron monstruos creados por los viejos dioses para
evitar que los dioes del Olimpo tomaran control del bajomundo.
Así que nombre más acertado para este lenguaje, difícilmente exista ;)
Alcance del Lenguaje
El lengueaje pretende dar acceso a un subset de C++ a través de sintaxis Python.
Es decir, la traducción a C++ será lo más directa posible evitando así cualquier
tipo de necesidad de traducción (bindings) para usar bibliotecas escritas tanto
en C como en C++. Sólo se asumen cosas en cuanto a interfaces provistas por la
STL, como
Forward Containers,
Iterators, etc. Para sacar
todo el jugo a Typhon los tipos de datos más complejos deben estar escritos
siguiendo el estilo de la STL (cosa que ya está pasando actualmente, las mejores
bibliotecas en C++ como gtkmm,
libxml2++,
cgicc, etc interaccionan bien
con la STL y proveen interfaces similares).
Sintaxis
En TyphonSyntax? está especificada la sintaxis del lenguaje, en notación
EBNF (o algo parecido,
está basado en la especificación de Python).
Definiciones
Acá vamos a ir agregando cosas que definamos en cuanto al lenguaje:
- Va a ser un subset de C++, que provea básicamente lo mismo que provee
Python. Cualquier cosa más allá de eso tendrá que hacerse en C++.
- Puede verse de la forma inversa, también va a ser un subset de python si lo
miramos desde el otro punto de vista (hay cosas como
yield
o formas
lambda
que no van a estar).
- No va a hardcodear tipos de datos. Sin embargo sí se va a asumir una
interfaz tipo STL. Es decir el foreach se traducirá a iteradores del
estilo de la STL. Para hacer un foreach sobre cualquier tipo, este tipo
va a tener que cumplir el modelo de
Forward Container
en el sentido definido por la STL.
- Se va a optimizar para el caso general (2004 (c) Alberto Bertogli :D).
Es decir, las cosas que se hacen más frecuentemente deberían ser la que mejor
soporte del lenguaje tengan.
Características aún no definidas
Modo de iterar una secuencia
Prioridad: Alta
En C++ tendríamos 2 formas básicas de traducir:
for item_t i in seq_t seq:
por copia y por referencia. A su vez, cada una de estas formas puede ser
constante o no, lo que nos da 4 posibilidades:
- Que
i
sea una copia al ítem en seq
- Que
i
sea una copia constante al ítem de seq
- Que
i
sea una referencia al ítem de seq
- Que
i
sea una referencia constante al ítem de seq
Hacer una copia sería costoso en varios casos (de hecho en todo tipo de dato
que ocupe más de lo que ocupa un puntero) y una copia constante sería demasiado
raro que tenga alguna utilidad práctica. Por lo que nos queda decidir entre
referencia o const referencia.
Probablemente lo más intuitivo (aunque no lo más seguro) sea tener una
referencia modificable, y es esto lo que debería usarse por omisión según la
premisa optimizar para el caso general . A esto se suma que iterar con una
referencia constante sería bastante claro con una construcción como:
for const item_t i in seq_t seq:
En el caso inverso no hay ninguna palabra reservada lo suficientemente clara y
realmente sería menos intuitivo (aunque menos suceptible a errores, al menos yo
tengo la teoría de que todo debería ser constante a menos que se pueda demostrar
que necesita ser variable :).
En caso de necesitarse una copia (querer modificar i
dentro del cuerpo del
for
sin que los cambios se reflejen en los ítems de seq
), siempre se puede
hacer una copia explícita:
for item_t i in seq_t seq:
item_t copia = i
copia += 2 * seq.size()
# etc.
Implementación
for item_t i in seq_t seq:
se traduciría:
for (seq_t::iterator ___i = seq.begin(); ___i != seq.end(); ++___i)
{
item_t& i = *___i; // Referencia
// ...
}
Mientras que:
for const item_t i in seq_t seq:
se traduciría:
for (seq_t::const_iterator ___i = seq.begin(); ___i != seq.end(); ++___i)
{
const item_t& i = *___i; // Referencia constante
// ...
}
Uso de typeof
Prioridad: Media
typeof()
es una extensión de GNU para C/C++, para obtener el tipo de una expresión en
tiempo de compilación. El uso de esta extensión simplificaría considerablemente
la implementación de la deducción de tipos para el for
y otras construcciones,
pudiéndose llegar a hacer prácticamente cualquier declaración de una variable con
tipo implícito (siempre y cuando se la inicialice en la declaración). Manteniendo
una tabla de símbolos y forward declarations podría evitarse el uso de
typeof
, pero los forward declarations pueden convertirse en algo muy tedioso
e inecesario. Como siempre, se puede llegar a un balance. La deducción de tipos
siempre será opcional (para poder tener mayor control de las variables), por lo
que puede agregarse algún tipo de opción al compilador (me refiero al traductor
de Typhon a C++) para hacer uso o no de typeof
. Si no se usa typeof
el
código tendrá que ser inevitablemente más redundante (tendrán que especificarse
los tipos de más variables explícitamente y usar forward declarations) pero
permitirá generar código ISO C++ que es una alta prioridad en Typhon.
Implementación
El principal uso sería en un bloque for
:
for i in seq:
se puede traducir a:
for (typeof(seq.begin()) ___i = seq.begin(); ___i != seq.end(); ++___i)
{
typeof(*___i)& i = *___i;
// ...
}
Sin tener absolutamente ninguna información sobre seq
, ni sobre el tipo de elemento
que contiene.
Esto podría llevarse más lejos y usar tipos implícitos:
int f(): return 5
int main():
n = f() # n es una declaración implícita, con el tipo de f(), en este caso int
return 0
esto se traduciría a:
int f()
{
return 5;
}
int main()
{
typeof(f()) n = f(); // n tiene el tipo devuelto por f(), gracias al uso de typeof
return 0;
}
De nuevo, a pesar de que pueda ser conveniente, me parece muy suceptible
a errores, ya que cualquier asignación se convertiría en una declaración
implícita, haciendo que un typo en el nombre de una variable sea un bug
muy difícil de encontrar (problema actual de la mayoría de los lenguajes
interpretados).
Palabra reservada auto
Una posible solución a esto, que mantendría un buen equilibrio entre
conveniencia y seguridad, sería agregar una palabra reservada como auto
para declarar una variable con tipo implícito (de hecho se propuso en
comp.lang.c++). El ejemplo anterior en Typhon sería:
int f(): return 5
int main():
auto n = f() # n es declarada con tipo implícito, obtenido de f(), en este caso int
return 0
De esta manera se puede distinguir claramente una declaración, pero dejamos
en manos del compilador la deducción del tipo. De manera que si alguien
tipea mal una variable en una asignación, no se crearía un símbolo nuevo y se
convertiría en un error de compilación.
Un ejemplo con más sentido sería el caso en que se queira iterar un contenedor
obteniendo una copia de cada ítem:
for i in seq:
auto copia = i
copia += 2 * seq.size()
# etc.
Por supuesto la declaración de una variable de tipo implícito deberá estar
acompañada siempre de su inicialización, de otra manera no se puede deducir
el tipo. Por lo tanto la expresión auto mi_var
(sin una asignación) es un
error de compilación.
Literales de strings
Prioridad: Media/Alta
Aún no sabemos que vamos a hacer con los strings largos y strings cortos
de Python.
Shortstrings
Prioridad: Alta
En principio los strings cortos deberían poder escribirse sólo con "
(comillas dobles) porque las '
(comillas simples) deberían usarse para
expresar literales char
como en C/C++.
Longstrings
Prioridad: Media
Con respecto a los string largos no sé si valga la pena traducirlos de
alguna forma o directamente no soportarlo, aunque creo que soportarlos no
traería grandes complicaciones y en ciertas circunstancias pueden ser
convenientes.
Prefijos
Prioridad: Media/Alta
También hay que definir si se soportan los prefijos (como r
para strings
raw, u
para unicode, etc). Tener en cuenta que traducirlos podría
romper la compatibilidad en ciertos ámbitos.
Strings traducibles
Prioridad: Media
También podría incluirse el prefijo _
introducido por D para marcars
strings traducibles. Esto podría integrarse con gettext u otros sistemas
de internacionalización. Lo bueno es que la forma de trabajar quedaría en
manos del lenguaje y en caso de cambiar de implementación, sólo habría que
cambiar el compilador. De hecho podría tener soporte para varios sistemas
de internacionalización.
Por otro lado, siguien la hipótesis de optimizar para el caso general,
podría tomarse por omisión a todos los strings como traducibles, excepto a
los que lleven el prefijo _
, ya que por lo general, la mayor parte de los
strings en un programa son traducibles.
Todo esto podría manejarse con opciones de línea de comandos a la hora de
compilar, por lo que sin ningún problema, y de forma transparente, podría
generase código sin ningún tipo de dependencia de un sistema de
internacionalización incluso cuando el código esté escrito para ser
internacionalizable.
Palabra reservada block
Prioridad: Baja
Serviría para hacer un bloque de código arbitrario. Es útil para técnicas
de programación como sentries.
Ejemplo:
include ifstream, string
import ifstream, string, getline from std
void f():
# Hago cosas ...
# Quiero obtener en una variable el contenido de un archivo
string contenido
block:
ifstream f("archivo")
string buffer
while getline(f, buffer):
contenido += buffer
# Listo, acá se destruye tanto f (se cierra el archivo) como buffer
# Usamos el contenido como más nos guste
Workarround
Esto podría emularse con:
if 1:
# código del bloque acá
Comentarios
Prioridad: Media
Comentarios multilínea
Prioridad: Media
A Python le falta comentarios multilínea, cosa que me resulta bastante
molesto.
Comentarios multilínea anidados
Prioridad: Media
D tiene comentarios anidados, cosa muy conveniente para comentar un
bloque de código grande que a su vez pueda tener comentarios adentro.
Me parecería piola que Typhon tenga algo similar.
Compilación condicional
Prioridad: Media
Meter cosas del precompilador en Typhon me parece poco conveniente,
pero hay cosas necesarias como la compilación condicional. D lo
soluciona con palabras clave version
, que es básicamente lo mismo
que un #ifdef ... #endif
del precompilador. Creo que Typhon podría
proveer algo similar. Por ejemplo:
version DEBUG:
void debug(string msg):
cerr << "debug: " << msg << "\n"
int main():
version DEBUG:
debug("entrando al main\n");
# Mas cosas
version LINUX:
# algo específico de Linux.
Luego para compilar podría haber un flag:
tyc -V DEBUG archivo.ty
Podrían definirse versiones estándar como en D, como LINUX
, WIN32
,
MACOS
, etc que se activen automáticamente dependiendo de la plataforma
en la que corra el compilador.
Todo esto puede traducirse de forma bastante inmediata y sin mayores
inconvenientes a directivas del precompilador.
class vs. struct
Prioridad: Alta
En C++ una clase y una estructura son exactamente igual, sólo que la clase
tiene visibilidad privada por omisión y el struct pública. Ninguna de las
dos hace virtuales sus métodos a menos que sea especificado explícitamente.
Las clases en la mayoría de los lenguajes de alto nivel son completamente
virtuales, sin posibilidad siquiera de que sea de otra forma. Incluso en
C++ el struct suele utilizarse para tipos de datos más simples y
concretos, que muy difícilmente tengan algún método virtual (aunque no hay
ninguna razón técnica que lo impida).
Siguendo esta línea y la premisa de optimizar para el caso general
probablemente sea una buena idea que las clases tengan todos sus métodos
virtuales por omisión y las estructuras no.
El problema de esto es que debería haber alguna palabra clave para hacer un
método no virtual, para tener una mayor flexibilidad y no tener que caer en
un struct con muchos métodos virtuales declarados explícitamente porque se
necesita que un método particular no sea virtual.
Visibilidad
Con respecto a la visibilidad por omisión, creo que es indiscutible que las
estructuras deben tener visibilidad pública, pero con las clases no es tan
claro. En los lenguajes interpretados, las clases suelen tener visibilidad
pública por omisión y los lenguajes más serios suelen tener visibilidad
privada. Que tenga visibilidad privada no tiene muchas más ventajas que dejar
contento a los abanderados de la orientación a objetos estricta (al menos
para mí :), por lo que probablemente lo más conveniente es que tanto las
clases como estructuras tengan visibilidad pública por omisión.
Lo mismo para la visibilidad en la herencia, en este caso creo que es mucho
más claro que lo más natural es que la herencia sea pública por omisión.
Herencia virtual
Es un caso muy poco frecuente y no creo que haya una mejor manera de
manejarlo que la de C++, así que creo que debería mantenerse la herencia
como no virtual por omisión pero permitir que lo sea si se lo especifica
explícitamente.
Ejemplo
class C:
C(): cout << "Constructor de C\n"
int hacer_algo(double i) const: return i/2
~C(): cout << "Destructor de C\n"
Se traduciría como:
struct C
{
C();
virtual int hacer_algo(double i) const;
virtual ~C();
};
C::C()
{
cout << "Constructor de C\n";
}
int C::hacer_algo(double i) const
{
return i/2;
}
C::~C()
{
cout << "Destructor de C\n";
}
Mientras que:
struct C:
C(): cout << "Constructor de C\n"
int hacer_algo(double i) const: return i/2
~C(): cout << "Destructor de C\n"
Se traduciría como:
struct C
{
C();
int hacer_algo(double i) const;
~C();
};
// ídem anterior
Nota: La declaración de C++ estaría en un .h
y la definición en un .cpp
.
Ejemplos
Los ejemplos se mudaron a TyphonExamples porque eran demasiado extensos.
Links
- The C++ Programming Language -
Lenguaje de programación compilado al cual se traducirá Typhon.
- Python - Lenguaje interpretado en el cual
Typhon va a basar su sintaxis.
- Standard Template Library -
Biblioteca estándar de C++, Typhon va a usar sus características e
interfaces para traducir secuencias y cosas similares.
- The D Programming Language -
Lenguaje compilado parecido a C++ pero con algunas caracteristicas de más
alto nivel y otras cosas muy interesantes, de las cuales tal vez podrían
agregarse un par a Typhon.
- Pyrex - Un
lenguaje que es prácticamente una extensión a python para mezclarlo con C,
diseñado específicamente para hacer bindings de C para Python. Fue una de
las fuentes de inspiración para Typhon.