Si diseñaras un lenguaje de programación, ¿cómo lo harías? ¿Qué características pondrías? ¿Qué dejarías fuera? ¿Mecanografiado estática o dinámicamente? ¿Fuerte o débilmente tipeado? Compilado o interpretado? Justifica tus respuestas.
programming-languages
language-design
Chinmay Kanchi
fuente
fuente
Respuestas:
Definitivamente creo que los lenguajes de programación funcionales se pondrán al día, por lo que mi lenguaje será funcional. Ver Efectos de domesticación con programación funcional
Creo que las CPU pronto tendrán cientos de núcleos, y los hilos serán un infierno para administrar. Entonces, el modelo de actor es imprescindible en lugar de hilos. Ver Erlang - software para un mundo concurrente
También creo que OOP ha fallado, se suponía que la comunicación entre objetos era asíncrona . Así que creo que necesitamos pasar mensajes , con mensajes inmutables. Enviar y olvidar. Como en el modelo de actor. Consulte Programación orientada a objetos: ¿el camino equivocado?
Creo que sería bueno tener una escritura estática , por lo que los errores se detectan antes en el ciclo de desarrollo. Pero usaría la inferencia de tipos como en Haskell, para que el desarrollador no necesite escribir el tipo en todas partes del código como en C, C # y Java. Vea Aprenda usted un Haskell para un gran bien
También diseñaría una gran biblioteca de interfaz de usuario , con diseño declarativo , como en WPF y Android. Pero me gustaría tenerlo como en la programación funcional reactiva .
Entonces, mi lenguaje sería como la concurrencia en Erlang pero con la escritura como en Haskell y un marco GUI como en WPF.NET.
fuente
Nota: He usado la sintaxis tipo C para describir las características en esta publicación, pero no soy exigente con la sintaxis en sí, siempre y cuando no sea algo ridículo como todas las palabras clave como MAYÚSCULAS.
1. sistema de mecanografía
La característica número uno que quisiera en un idioma es la escritura estática con la escritura dinámica opcional . La razón es que la escritura estática le permite a) detectar errores temprano en lugar de tarde yb) la mayoría del código está tipado estáticamente de forma implícita, independientemente de si el idioma hace o no la distinción. Sin embargo, hay varios casos de uso donde la tipificación dinámica es extremadamente útil. Por ejemplo, cuando lee datos de un archivo, a menudo tiene campos de diferentes tipos, y la escritura dinámica facilita los contenedores heterogéneos. Entonces, mi lenguaje ideal tendría algo como esto:
2. Compilado vs. Interpretado
Me gustaría que el lenguaje se compile con anticipación o que se compile JIT, pero no se interprete puramente, siendo la razón la velocidad. Esto se relaciona con el punto 1 , ya que un compilador / jitter optimizador tendrá mucho más tiempo optimizando el código tipado estáticamente, y el código tipado dinámicamente simplemente podría dejarse como está.
3. Cierres
El lenguaje debe admitir construcciones de programación funcional, y las funciones deben ser objetos de primera clase.
4. Orientado a objetos
El lenguaje debería permitirle escribir código orientado a objetos, pero también debería permitirse un código imperativo simple. es decir, debería ser posible escribir un programa hello world así:
5. Espacios de nombres
Los espacios de nombres son algo bueno. Muy pocas cosas deberían ir al espacio de nombres global. Pero si debe poner cosas en el espacio de nombres global, puede (ala C ++).
6. Tipos de datos incorporados
El lenguaje debe tener, como tipos de datos integrados, las siguientes construcciones:
int
tipo de datos o tipos. Si solo hay unint
tipo, debe tener un rango ilimitado. Si hay más, debería haber una conversión implícita en el tipo más pequeño capaz de contener el resultado de un cálculo, siendo el tipo de rango ilimitado el más grande.float
tipo binario incorporado , que es equivalente a un IEEE 754double
list
tipo mutable que se implementa como una lista doblemente vinculada o como un bloque de memoria contigua que contiene punteros a cada elementolist
tipo inmutable que actúa como una matriz pero cuyo tamaño no se puede cambiar después de la creación.string
Tipos mutables e inmutables , siendo el valor predeterminado inmutable.map
odict
tipo que es mutable, y tiene teclas inmutables y valores mutables y / o inmutables.vartype
d si es necesarioboolean
tiponull
onone
tipo que se puede asignar a una variable de cualquier tipo.set
Tipos mutables e inmutablesdecimal
tipo que implementa variables de coma flotante decimalfixed
tipo, que implementa un número de punto fijoLos tipos
decimal
,float
yfixed
deben compartir exactamente la misma interfaz pública (ya sea a través de la herencia o la escritura de pato), lo que les permite pasar de forma transparente y regresar de las funciones. Se podría llamar al tipo principalreal
.7. Llamada por valor y por referencia
Debería poder llamar a las funciones tanto por valor como por referencia, siendo el valor predeterminado (es decir, se realiza una copia del argumento y se opera en la función).
8. Punteros
El lenguaje debe tener punteros y permitir aritmética de punteros. Los punteros solo se pueden escribir estáticamente (para evitar la pesadilla que es a
void*
).vartype
los punteros están explícitamente prohibidos Tener punteros y aritmética de punteros permite que el lenguaje se use seriamente como lenguaje de programación de sistemas.9. montaje en línea
En relación con 8. , El idioma debe permitir el código de lenguaje ensamblador en línea para aquellas situaciones donde sea necesario.
10. seguridad
El lenguaje debe ser seguro de usar, admitir el manejo de excepciones, etc. La aritmética del puntero y el ensamblaje en línea pueden relegarse a partes del código marcadas explícitamente como inseguras. Se permite código inseguro, pero se desaconseja encarecidamente.
11. Comportamiento indefinido
El estándar del lenguaje debe especificar cómo se comportará el programa en todas las circunstancias, excepto en el código marcado explícitamente como inseguro, es decir, no debe haber un comportamiento indefinido fuera de los bloques inseguros. Esto permite que el lenguaje se use como un lenguaje de desarrollo de aplicaciones viable, al tiempo que le permite decir, escribir un sistema operativo en él.
Eso es todo lo que puedo pensar en este momento, pero editaré / actualizaré la publicación a medida que piense en más cosas.
fuente
decimal
tipo aquí.Así es como se vería el lenguaje de programación de mis sueños:
fuente
yield
en Smalltalk? Debe ser tan limpio de usar.Lo hubiera diseñado más o menos como C #, pero Microsoft me ganó. :)
(Excepto, por supuesto, que el mío hubiera sido menos pensado y más aficionado).
No me importa mucho si está compilado o interpretado, así que no necesito justificar ese bit.
En cuanto a la tipificación estática fuerte, me resulta difícil apreciar por qué esto incluso requiere justificación. La escritura estática es una característica que detecta errores durante el tiempo de compilación. La escritura dinámica es la falta de esa característica y difiere los errores hasta el tiempo de ejecución. En mi experiencia personal, tuve pocos casos de uso donde el despacho dinámico tenía sentido y era útil, por lo que las convoluciones que tuve que atravesar en C # antes de 4.0 para obtenerlo se justificaron fácilmente en ese momento. Con C # 4.0 ya ni siquiera necesito justificar eso porque ahora tenemos un despacho dinámico.
Sin embargo, probablemente habría creado una nueva sintaxis en lugar de apegarme tan religiosamente a la vieja sintaxis de C como lo hizo C #. La declaración de cambio es particularmente horrible, y tampoco me gusta la sintaxis de transmisión (es al revés). Sin embargo, no hago un gran alboroto sobre los detalles de la sintaxis, por lo que no necesito justificarlo en detalle, excepto que no quisiera que sea tan detallado como Visual Basic.
¿Qué más quieres que justifique?
fuente
Bueno, aquí hay una lista de características que pondría:
Lisp como sintaxis
Estilo Lisp
Pros :
(eval "your data files")
Contras :
Programacion Funcional
Estilo Haskell
Pros :
Contras :
Fuerte tipificación dinámica
Estilo Python
Pros :
implementación :
Permitir la sobrecarga de funciones en función de los tipos, similares a los CL
defgeneric
:Compilable e Interpretable
Pros :
Contras :
Programación de sistemas
Estilo C
Pros :
Contras :
Macros higiénicas (estilo CL y estilo Scheme)
Pros :
Contras :
Ahora que lo pienso, este esquema más o menos define, a excepción del bit de compilación y programación de sistemas. Eso se puede solucionar usando libguile y escribiendo esos bits en C.
fuente
car
es la función ycdr
los argumentos, tiene un objeto cuyoname
ámbito es el método y cuyoarguments
campo es el argumento y en lugar de anidación, que tiene.prev
ynext
puntero campos).Hay varios idiomas que considero bastante buenos (C # es mi favorito actual). Como este es mi lenguaje de fantasía, esto es lo que realmente quiero que tenga:
fuente
Sugerencias del compilador
Estoy hablando de mí porque no sé mucho sobre el diseño del lenguaje, pero creo que la característica de la que estoy hablando se llama pistas en otros idiomas. Consejos del compilador , tal vez?
No sé si leí esto en un borrador de Perl6 o solo estaba alto en ese momento, pero me imagino un lenguaje en el que todo, por defecto, es flojo, pegajoso y automático. Pero si realmente desea aumentar el rendimiento y decir, oye, este valor siempre es un número entero o nunca es nulo, o puede ser paralelo, o no tiene estado, cosas así ... Que el compilador podría ir automáticamente a la ciudad en estas áreas marcadas específicamente.
E: Agradecería comentarios que aclaren lo que estoy pidiendo o que citen ejemplos donde esto ya existe.
fuente
safety
yspeed
, a menudo puede hacer que el compilador verifique y aplique (para encontrar problemas) o suponga que lo que dice es verdadero (y compila código más rápido).Para probar nuevas ideas:
Haría un lenguaje de programación funcional de tipo dinámico, que le permite hacer todos los trucos de expresión de enunciados y la sintaxis lambda más simple con coincidencia de patrones. Regla fuera de juego habilitada.
Aquí hay una explicación:
default =
establece el almacenamiento,\def val
se inicia una función de curry con dos argumentos,val.Type
es el mismo queType[val]
,!!
convertidos a Boolean, y boolean se puede aplicar, por lo queval
ydef are after it.
f x
=f[x]
=x.f
.f
=f[]
y en
greet
, se utilizaname<(default "world")
yhasType Str>
, significa que el patróndefault "world"
será utilizada y obligado aname
. El patrón predeterminado especifica un valor predeterminado.and
es otro patrón que encadena dos patrones juntos. eldefault
patrón no puede fallar mientras quehasType
puede fallar. En ese caso, arroja una excepción.Las variables son en realidad almacenamientos, que pueden pasarse funcionalmente, y las tablas de almacenamiento pueden ser referencias, creadas y destruidas a medida que cambian los ámbitos.
Los hashes y demás serán como en Lua y JavaScript.
Si voy a hacer un lenguaje compilado, voy a hacer un F # para Java, con características similares a las de Haskell. Es un lenguaje funcional puro, excepto que hay una característica que combina las citas y las explicaciones de compilación para lograr una programación imperativa escribiendo bloques de tipo pseudocódigo.
fuente
Teniendo en cuenta que los únicos lenguajes que conozco son PHP y JavaScript, y que realmente debería aprender algunos más antes de diseñar un lenguaje:
Sintaxis: piense detenidamente sobre los nombres de las funciones y el orden de los argumentos (es decir, sea menos complicado que PHP).
Características: tiene un conjunto de
string
funciones, que operan en variables como una serie de bytes, pero no entienden el texto, y un conjunto detext
funciones, que entienden muchas codificaciones y pueden operar en UTF-8 y otras cadenas multibyte. (Y tenga controles de sanidad de codificación integrados en el lenguaje, con una función como latext.isValidEncoding(text, encoding)
que le indicará si una secuencia de bytes tiene un formato incorrecto y no es seguro tratarla como texto.Creo que me gusta la idea del tipeo estático fuerte, pero nunca la he usado, por lo que realmente no puedo decirlo.
fuente
Antes de diseñar un lenguaje de programación, encontraría una buena respuesta a la pregunta: ¿por qué necesitamos otro lenguaje de programación más? El Código de Rosetta al momento de escribir esto enumera 344 idiomas. Si ninguno de esos satisface mis necesidades, los detalles específicos de por qué no determinarían el punto de partida (los idiomas que se acercan más) y lo que se agregaría.
Si ganara la lotería y, por alguna razón, no tuviera nada mejor que hacer, comenzaría con Liskell y lo convertiría en un lenguaje completo en lugar de un front-end de GHC, luego haría que FFI sea más fácil (y automatizado) para poder usar cualquier Biblioteca C / C ++.
fuente
Un buen idioma es un idioma que es:
Es bastante difícil convertir esto en una lista de características, pero creo que la programación funcional, a pesar de no sentirse natural , está más cerca de esto que la programación imperativa (especialmente al ocultar los detalles esenciales)
Por el momento, el idioma más cercano a esta lista es probablemente Haskell:
fuente
A su primera pregunta, "¿cómo lo haría?" - respuesta corta, no lo haría. No tengo suficiente teoría del analizador / compilador para lograrlo. Pero llevo 25 años programando, así que tengo algunas ideas y opiniones que compartir.
En primer lugar, trataría de llegar a un enfoque OOP que le permita crear modelos verdaderamente conectados. Lo que quiero decir con eso es que los modelos son una de las cosas más importantes en casi cualquier tipo de proyecto de programación: siempre es un trabajo duro y una refactorización continua para hacerlo bien, y culpo eso a la falta de conectividad real en OO idiomas.
Permíteme demostrarlo. Digamos que una casa de clase tiene una propiedad de puerta.
Ahora tiene una variable local con una referencia a la instancia de Door.
Pero considere lo que acaba de suceder: acaba de arrancar la puerta de la casa, y ahora está muy feliz de pasar la puerta, y el resto de su código ignora el hecho de que esta puerta está realmente unida a una casa.
Para mí, esto es fundamentalmente incorrecto.
Y sí, lo sé, esto se soluciona "fácilmente" caso por caso, en este caso manteniendo una referencia inversa de cada Puerta de la Casa a la que está conectada actualmente. Por supuesto, esto abre su modelo a errores, ya que ahora es su deber mantener con precisión dos referencias inversas, por lo que hace que las propiedades House.Doors y Door.House sean privadas, y agrega métodos como House.AddDoor (), House.RemoveDoor ( ), Door.SetHouse (), etc., conéctelo todo y realice una prueba unitaria para asegurarse de que realmente funciona.
¿No está empezando a parecer mucho trabajo para modelar una relación tan directa? ¿Mucho código para mantener? ¿Mucho código para refactorizar a medida que el modelo evoluciona?
El problema son los punteros. Todos los lenguajes OO que he visto sufren de manera inherente el hecho de que una referencia de objeto es realmente un puntero, porque eso es lo que usan las computadoras.
Los punteros no son una buena forma de modelar el mundo real. Independientemente del mundo que intente modelar, es casi seguro que cualquier relación en ese mundo será de dos vías. Los punteros apuntan en una sola dirección.
Me gustaría ver un lenguaje donde el modelo de datos fundamental es un gráfico, donde todas las relaciones, por defecto, tienen dos extremos. Es casi seguro que esto proporcionaría un ajuste mucho más natural para modelar el mundo real, que en realidad es lo único para lo que necesitamos computadoras en primer lugar. (eso y los videojuegos).
No tengo idea de cómo se vería la sintaxis para un lenguaje de este tipo, o si incluso se puede expresar con texto. (Me preguntaba si ese lenguaje tendría que ser gráfico, de alguna manera ...)
También me gustaría ver todas las formas de estado accidental eliminado.
Por ejemplo, en el desarrollo web, pasamos mucho tiempo formando datos de bases de datos, en modelos de negocio, en modelos de vista para presentación ... luego, algunos de esos datos se presentan en formularios, lo que en realidad es solo otra transformación. ... y el estado regresa de las publicaciones de formulario, y luego volvemos a dar forma a esos datos y los proyectamos de nuevo en el modelo de vista, por ejemplo, carpetas de modelos de vista y tal ... luego proyectamos desde el modelo de vista de nuevo en el negocio- modelo ... luego usamos mapeadores relacionales de objetos (o trabajo gruñido) para transformar los datos del modelo de vista y proyectarlos en una base de datos relacional ...
¿Esto comienza a sonar redundante? ¿En qué punto durante toda esta locura realmente logramos algo útil? Y por útil quiero decir, algo tangible, algo que el usuario final puede entender y le importa. Al final del día, las horas que dedicó a construir algo que los usuarios pueden entender, en realidad son las únicas horas bien empleadas. Todo lo demás son efectos secundarios.
Quisiera un lenguaje altamente dinámico. El ciclo de escritura / compilación / ejecución es una tediosa pérdida de tiempo. Idealmente, el lenguaje debería descubrir qué cambió y compilar / cargar de forma transparente, en segundo plano, según sea necesario.
Idealmente, ni siquiera debería tener que presionar "ejecutar": las cosas deberían suceder en la pantalla, a medida que realiza cambios, que reflejan inmediatamente los cambios que realiza. El problema con el ciclo de escritura / compilación / ejecución, o incluso para el ciclo de escritura / ejecución más directo, es que estás demasiado desconectado de lo que estás haciendo, para sentirte conectado con nuestro trabajo, nosotros Necesita comentarios inmediatos, resultados instantáneos. ¡Cualquier espera es demasiado larga!
Nuevamente, ni siquiera sé si esto podría lograrse con un IDE tradicional, o si esto requeriría un tipo de interfaz completamente nuevo.
Debería poder usar una combinación de mecanografía débil y fuerte, lo que sea más adecuado para el problema en el que está trabajando.
El estado en general debería ser algo que el lenguaje maneje completamente para usted. ¿Por qué debería necesitar confiar en una base de datos para la persistencia? Idealmente, me gustaría poder especificar simplemente el período de vida de cualquier variable en el modelo: una solicitud web, una sesión, 24 horas, de forma permanente.
¿Por qué tenemos que elegir entre una amplia gama de soluciones de almacenamiento para diferentes medios y plazos de vida? - sin mencionar la transformación y la configuración de los datos para adaptarse a cada medio; caché del navegador, base de datos, memoria, disco, ¡a quién le importa! Los datos son datos. ¡Dónde almacenar sus datos (y por cuánto tiempo) debería ser una elección simple, no una batalla contra los Dioses!
Bueno, buena suerte con eso.
fuente
Probablemente sea un lenguaje de paradigma múltiple, que soporte lo siguiente:
¿Por qué estos? Orientado a objetos porque es una excelente manera de organizar grandes programas, especialmente para organizar los datos. Estructurado porque no siempre quieres / necesitas eso (OOP), las personas deberían tener opciones. Funcional porque facilita la depuración de los programadores y hace que los programas sean más claros.
Usaría el modelo de Python con bloques sangrados para marcar bloques de código. Es muy claro y agradable de leer.
En realidad, robaría muchas ideas de Python porque Python es un lenguaje muy agradable. Lo tomaría como una declaración y copiaría sus mapas, listas y tuplas.
Ahora, probablemente no tomaría los conceptos dinámicos de Python: por un lado, probablemente sería tipado explícita y estáticamente. Creo que los programas se vuelven más claros con eso. Probablemente todas las variables serían objetos con métodos, entonces podría hacer algo como
str.length()
obtener la longitud de una cadena. En las definiciones de funciones, debería especificar el tipo de retorno y los tipos de argumentos (que también admiten algún tipo de tipos genéricos).Volvamos a copiar desde Python ;-). Me encanta su forma de tener argumentos de procedimiento opcionales, así que probablemente lo tenga. Sin embargo, Python no admite la sobrecarga de procedimientos, me gustaría eso.
Veamos las clases, abandonaría la herencia múltiple; a fácil de abusar. Implementaría ámbitos privados y similares y probablemente lo implementaría de la forma en que se hace en C ++. También tendría clases abstractas e interfaces; No creo que Python tenga eso.
Sería compatible con las clases internas, de hecho, me gustaría un lenguaje orientado a objetos muy poderoso.
Probablemente sería interpretado. Es posible hacerlo realmente rápido usando una buena compilación JIT (me gustaría un lenguaje rápido, aunque la productividad del programador sería lo primero) y la compilación es simplemente mala para la productividad en muchas ocasiones. Los idiomas interpretados también promueven la independencia de la plataforma, algo que importa cada vez más para cada día.
Tendría soporte incorporado de Unicode; En estos días la internacionalización es muy importante.
Definitivamente sería basura recolectada. Maldición, odio hacer la administración de la memoria yo mismo; No es bueno para la productividad tampoco.
Finalmente, tendría una buena biblioteca estándar.
Wow, me acabo de dar cuenta de lo mucho que amo Python.
fuente
Interpreted languages also promote platform independance
? Supongo que hay más intérpretes multiplataforma en lugar de compiladores (porcentaje), pero no podría entender por qué esta oración debería ser cierta. Creo que no hay diferencia entre ellos en lo que respecta a las habilidades multiplataforma.En primer lugar, compraría algunos libros sobre compiladores, algunos estándares y tomaría un curso o dos en idiomas y compiladores. Contribuiría con PEP y visitaría las reuniones del comité de estándares de C ++. Contribuiría con parches a los compiladores que uso, con suerte tanto para características como para errores.
Luego regresaría y miraría con horror esta lista que he encontrado ahora, que es de qué direcciones seguiría con un idioma si comenzara en este momento:
Dado que incluso estos puntos bastante amplios probablemente cambiarían rápidamente si comenzara a implementar el lenguaje, creo que no es necesario entrar en más detalles.
fuente
Si tuviera tiempo, diseñaría un lenguaje de programación localizable basado en Scala, por lo que tendría la mayoría de sus características, excepto probablemente el XML. Mi objetivo es crear un idioma que se lea casi naturalmente en idiomas con una estructura diferente al inglés, como el árabe (mi lengua materna). Estoy pensando en las siguientes características:
#lang
directiva de preprocesador , utilizada para informar al preprocesador del lenguaje humano utilizado para la programación. Por ejemplo:#lang ar
permitiría el uso de la palabra enفئة
lugar declass
, enعرف
lugar dedef
, etc. Las palabras clave específicas del lenguaje humano se definirían en archivos de preprocesador estándar.class MyClass is composed of {
convertirseclass MyClass {
y eliminaría "como" endef MyMethod(x: Int) as {
convertirsedef MyMethod(x: Int) {
. En algunos idiomas (humanos), esto haría que el código sea mucho más fácil de entender, especialmente para los estudiantes.اعرض طول اسم محمد
, que es equivalente aprint(length(name(Mohammad)))
en programación en inglés. (Los paréntesis son para mayor claridad).Creo que estos cambios mínimos en el preprocesador y el compilador harán que la programación sea mucho más simple para los que no hablan inglés.
fuente
print
) no estaría de más.