<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml"/><link href="/" rel="alternate" type="text/html"/><updated>2026-04-17T20:35:29+02:00</updated><id>/feed.xml</id><entry><title type="html">What if the Web was not hypertext?</title><link href="/blog/what-if-the-web-was-not-hypertext" rel="alternate" type="text/html" title="What if the Web was not hypertext?"/><published>2026-01-21T00:00:00+01:00</published><updated>2026-01-21T00:00:00+01:00</updated><id>/blog/what-if-the-web-was-not-hypertext</id><content type="html" xml:base="/blog/what-if-the-web-was-not-hypertext"><![CDATA[<p><small> Translated from <a href="/blog/y-si-la-web-no-fuera-hipertexto">¿Y si la web no fuera hipertexto?</a> </small></p> <h2 id="starting-point">Starting Point</h2> <p>The state of education and general culture regarding the internet and the World Wide Web is, to say the least, worrying. The cloud, web applications, social networks, and other byproducts of the latest evolutions of the Web (with the recent incorporation of generative AI services) form an ecosystem that people without a technical background rarely escape. Users are trained in specific interfaces to use specific products, and there are very few software tools outside this limited set that users are willing to learn. When your judgment is limited to user-level knowledge, the reasoning is understandable: why learn an alternative if I already know how to use something and it’s easier? This is the main reason why Linux and much Free Software have failed to achieve broader adoption. This is the problem we continue to face when offering free alternatives: a barrier to entry created by user-experience design and an ecosystem hostile to alternative technologies.</p> <p>However, there is one exception to this rule: a type of software that is not used as a means to an external task, but as an end in itself—video games. These are not tools used with the expectation of producing results; they are run for playful, aesthetic, or purely curious interest. For this reason, they are a perfect gateway for educating the population, just as they have also been used for manipulation. Not only because the gamified content format predisposes users to absorb it, but because the game itself belongs to the very medium one wants to teach about. There is no better way to explore the possibilities and risks of a computer than from within one.</p> <h2 id="development-of-dw3nd3">Development of dw3nd3</h2> <p>With this framework, the history of dw3nd3 becomes easier to understand. Initially, it was born as a lightning project after discovering <a href="https://twtxt.dev">twtxt</a>. I have long been interested in web decentralization, and it was twtxt that helped me rediscover the possibility of connecting decentralized content through protocols implemented in local clients. I had known about RSS for a long time, and of course HTML; but I had forgotten the fundamental principle of the web, because every time I considered <a href="https://dither8.xyz/blog/the-web-is-important/">writing my own browser</a>, I realized it was an almost unmanageable task. An RSS reader would be simpler, but it would still require a complex XML parser. By contrast, I could implement a twtxt browser in a matter of hours. After successfully doing so and rediscovering the potential of protocols based on simple rules and grammars, the question arose: couldn’t a video game be created using the same underlying idea?</p> <p>It was at this point that the story of dw3nd3 truly began. When thinking about a video game that navigates web content, it made sense to think of that game as a browser. I needed a simple format—easy to implement, understand, and replicate. I drew inspiration from twtxt, as mentioned, but also from <a href="https://100r.co/site/uxn.html">100 Rabbits’ work on the minimalist uxn stack</a>, from minimal educational environments such as <a href="https://toolbox.academy">toolbox.academy</a>, and from digital toys like the Tamagotchi. I decided to adopt the philosophy of using constraints as a creative springboard and informally defined the principles of dw3nd3: a functional client should be implementable in at most a couple of days, for an extensible data format that prioritizes backward compatibility. In this way, future users of d33 could create their own content without fear of it becoming obsolete, or experiment with modifications to the standard in their own clients without much effort.</p> <p>Then came the idea of hiding the contents of this web inside HTML pages. From there, the symbol of the <em>duende</em> emerged as something small and hidden; instead of web pages, the central concept would be that of <em>duende</em> rooms. Because the language was so small, a room could even fit inside social-media posts or comments. Later on, this idea expanded to include rooms embedded in other polyglot formats, so that the network of <em>duende</em> rooms could propagate not only through HTML pages, but also through code, documents, images, and more.</p> <p>As I refined an initial version of the standard while working on a proof-of-concept client, I realized that a browser needed a plugin-oriented architecture to fully unleash user creativity and take advantage of the standard’s flexibility. With this in mind, I designed the first version of tr4sg0, intended as a definitive reference for other clients.</p> <h2 id="lessons-from-dw3nd3">Lessons from dw3nd3</h2> <p>When I finished this work, I did not feel that I had truly <em>learned</em> something new, but rather that I had reconnected with a series of essential fundamentals as a computer scientist:</p> <ul> <li>The complexity of formal languages matters.</li> <li>The fundamental pillar of how the web works is standardization.</li> <li>Everything that exists on the web can have something hidden inside it.</li> </ul> <p>In my case, this project has had a re-educational value in addition to a creative one. If I could experience these truths from scratch thanks to d33, I thought that encouraging other users to create their own rooms, plugins, and even clients could do the same for them.</p> <p>We need to understand the web again, to revalue simple, replicable, and standardized software, and to understand the nature of the information that travels across the network. In all of this, dw3nd3 is only a small personal, creative, and experimental project—but it is born from that same awareness and aims to make its own small contribution.</p>]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[Translated from ¿Y si la web no fuera hipertexto?]]></summary></entry><entry><title type="html">¿Y si la web no fuera hipertexto?</title><link href="/blog/y-si-la-web-no-fuera-hipertexto" rel="alternate" type="text/html" title="¿Y si la web no fuera hipertexto?"/><published>2026-01-21T00:00:00+01:00</published><updated>2026-01-21T00:00:00+01:00</updated><id>/blog/y-si-la-web-no-fuera-hipertexto</id><content type="html" xml:base="/blog/y-si-la-web-no-fuera-hipertexto"><![CDATA[<h2 id="punto-de-partida">Punto de partida</h2> <p>El estado de la educación y la cultura general con respecto a internet y a la www es, como poco, preocupante. La nube, las aplicaciones web, las redes sociales y otros subproductos de las últimas evoluciones de la Web (con la reciente incorporación de los servicios de IA generativa), forman un ecosistema del que rara vez escapa la gente sin trasfondo técnico. Se entrena a los usuarios en interfaces específicas para que utilicen productos específicos, y son pocas las excepciones de herramientas software que los usuarios están dispuestos a aprender a utilizar, fuera de este limitado conjunto de productos. Cuando tu criterio está limitado a un conocimiento de nivel usuario, el motivo es razonable: ¿por qué aprender una alternativa si ya sé usar algo y es más fácil? Esta es la principal razón por la que Linux y mucho Software Libre no consigue una mayor adopción. Este es el problema al que nos seguimos teniendo que enfrentar para ofrecer alternativas libres: una barrera de entrada en los diseños de la experiencia de usuario y un ecosistema hostil a las tecnologías alternativas.</p> <p>Sin embargo, hay una excepción a esta norma, un tipo de software que no se utiliza para una tarea externa, sino como un fin en sí mismo: los videojuegos. Estos no son herramientas que se usen esperando unos resultados, sino que se ejecutan por un interés lúdico, estético o por curiosidad. Por eso, son una puerta de entrada perfecta para educar a la población, como también lo han sido para su manipulación. No solo porque el formato del contenido gamificado predispone al usuario a su asimilación, sino porque el propio juego pertenece al medio sobre el que se quiere educar. No hay mejor manera de explorar las posibilidades y riesgos de un ordenador que desde uno.</p> <h2 id="desarrollo-de-dw3nd3">Desarrollo de dw3nd3</h2> <p>Con este marco, se entiende mejor la historia de dw3nd3. En primera instancia, nació como un proyecto relámpago, después de conocer <a href="https://twtxt.dev">twtxt</a>. Llevo mucho tiempo interesado en la descentralización de la web, y fue twtxt lo que me redescubrió la posibilidad de conectar el contenido descentralizado mediante protocolos implementados en clientes locales. Hace mucho que conocía RSS, y lógicamente HTML; pero había olvidado el principio fundamental de la web, porque cada vez que me planteaba <a href="https://dither8.xyz/blog/the-web-is-important/">escribir mi propio navegador</a>, me daba cuenta de que era una tarea casi inabarcable. Un lector RSS sería más sencillo, pero siempre necesitaría un parser complejo para el XML. Sin embargo, podía implementar un navegador de twtxt en unas horas. Después de hacer con éxito dicha implementación y redescubrir el potencial de los protocolos basados en reglas sencillas y gramáticas simples, me vino la pregunta de si no podría crearse un videojuego que utilizase la misma idea de base.</p> <p>Fue en este punto donde comenzó la historia de dw3nd3. Al pensar en un videojuego que navegara por contenido en la web, lo lógico era considerar dicho videojuego como un navegador. Necesitaba un formato sencillo, para que fuera fácil de implementar, entender y replicar. Me inspiré en twtxt, como he mencionado, pero también en <a href="https://100r.co/site/uxn.html">el trabajo de 100 rabbits con su stack minimalista de uxn</a>, en entornos mínimos de enseñanza como <a href="https://toolbox.academy">toolbox.academy</a> y a jueguetes digitales como el tamagotchi. Decidí adoptar la filosofía de usar las restricciones como trampolín creativo y definí informalmente los principios de dw3nd3: un cliente funcional debía ser implementable en un par de días como máximo, para un formato de datos extensible que priorizara la retrocompatibilidad. De esta manera, los futuros usuarios de d33 podrían crear su propio contenido sin miedo a que se quedara obsoleto, o a probar modificaciones en el estándar con sus propios clientes sin mucho esfuerzo.</p> <p>Después vino la idea de poder esconder los contenidos de esta web en las páginas HTML. A partir de ahí, apareció el símbolo del duende como algo pequeño y oculto; en lugar de páginas web, el concepto central sería el de habitaciones duende. Al ser un lenguaje tan pequeño, una habitación podría caber incluso en publicaciones o comentarios de redes sociales; más adelante, esta idea pasó a incluir las habitaciones en otros formatos políglotas, de manera que la red de habitaciones duende podía propagarse no solo en páginas HTML, sino código, documentos, imágenes, etc.</p> <p>Al ir refinando una primera versión del estándar, trabajando con una prueba de concepto de cliente, me di cuenta de que un navegador necesitaba una arquitectura orientada a plugins para dar total rienda suelta a la creatividad del usuario y aprovechar la flexiibilidad del estándar. Con esto en mente, diseñé la primera versión de tr4sg0, a modo de referencia definitiva para otros clientes.</p> <h2 id="aprendizajes-de-dw3nd3">Aprendizajes de dw3nd3</h2> <p>Al terminar este trabajo, no sentí que huiera realmente <em>aprendido</em> algo nuevo, pero sí que había reconectado con una serie de fundamentos esenciales como informático:</p> <ul> <li>La complejidad de los lenguajes formales importa.</li> <li>El pilar fundamental del funcionamiento de la web es la estandarización.</li> <li>Todo lo que existe en la web puede tener algo escondido.</li> </ul> <p>En mi caso, he encontrado un valor re-educativo en este proyecto, además de creativo. Si yo podía experimentar estas verdades desde cero gracias a d33, pensé que animar a otros usuarios a crear sus propias habitaciones, plugins y hasta clientes, podría hacer lo mismo por ellos.</p> <p>Necesitamos volver a entender la web, volver a valorar el software sencillo, replicable y estandarizado, y entender la naturaleza de la información que viaja por la red. En todo ello, dw3nd3 sólo es un pequeño proyecto personal, creativo y experimental, pero que nace de esa misma conciencia y pretende hacer su pequeña aportación para ello.</p>]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[Punto de partida]]></summary></entry><entry><title type="html">Código humano</title><link href="/blog/codigo-humano" rel="alternate" type="text/html" title="Código humano"/><published>2025-12-24T00:00:00+01:00</published><updated>2025-12-24T00:00:00+01:00</updated><id>/blog/codigo-humano</id><content type="html" xml:base="/blog/codigo-humano"><![CDATA[<p>Una perspectiva poco compartida sobre la naturaleza del código es lo que se puede saber de una persona por su manera de escribirlo. Algo así tenía en mente cuando escribí sobre <a href="https://miguelmj.dev/blog/programming-as-a-conversation-how-the-communicative-scheme-is-also-applied-in-the-written-code-itself">la programación como conversación</a>, pero en aquel entonces no había leído tanto código escrito por IA. No voy a entrar en cuestiones como la productividad, la calidad del código ni métricas software o buenas prácticas; estas incumben a la industria, y ahora quiero hablar de la programación como actividad humana.</p> <p><strong>Creo que puedo recordar cada vez que he sentido la impresión de otra persona al leer su código</strong>. Y hablo de pasar a relacionarse con el código de manera cotidiana; no leer un fichero, una o dos funciones, sino a leer, día tras días, las líneas escritas por otro; a comprender un sistema de su autoría. Al hablar de textos narrativos, poéticos, diarios, cartas… la presencia de la persona nos llega a través de un lenguaje humano, el mismo lenguaje que usaría para hablarnos por la calle. Sin embargo, en el código se mezclan las imposiciones de un lenguaje formal y la definición de un algoritmo. Aun así, la personalidad del programador asoma en el conocimiento de sus herramientas, la comprensión del problema a solucionar y la forma de expresar estas soluciones, incluso cuando está mediada por convenciones y estándares. A menudo, <strong>a los programadores nos gusta que el código tenga cierto aspecto</strong>, cierta manera de leerse; eso después se convierte en convenciones de estilo, pero nace como una elección personal que persigue una subjetiva legibilidad. Incluso la ausencia de esta intención construye una identidad. Me pasa incluso cuando leo mi propio código, que tengo una reminiscencia de cómo era yo cuando lo escribí; qué me interesaba probar, con qué técnicas había adquirido soltura, o qué conocimientos no tenía todavía.</p> <p>Por eso, he tenido la sensación, algunas veces, de que <strong>se crea una pequeña intimidad en esa lectura de código</strong>. Es una pequeña ventana a cómo funciona la maquinaria mental de otra persona. Cuando se trabaja en proyectos en equipo, llegas a reconocer de un vistazo al autor de trozos de código sin necesidad de preguntar. Y esta forma de conocimiento, a mí, me resulta entrañable incluso cuando maldigo a la persona que escribió semejante espagueti. Porque otras veces, si es un buen código, el autor te comunica cómo programar mejor; y cuando no lo es, llegas a compartir la confusión que pudo tener que soportar, o como mínimo, a empatizar con su nivel de experiencia, porque todos hemos empezado en algún lado.</p> <p>Cuando estoy programando un sistema un poco más complejo, me da la sensación de estar sosteniendo un pequeño edificio con la mente, y que al pasarlo a código, lo dejo plasmado en él. Como cualquier proceso técnico creativo, en ocasiones tiene un punto solitario. Y al leer el código de otra persona, al ver su elección de arquitectura, qué prácticas usa y cuáles no, voy reconstruyendo el edificio que él/ella sostuvo mentalmente en algún momento. Es como ponerse en sus zapatos. Al hacer eso muchas veces, adquieres familiaridad con su forma de trabajo, reconoces cómo estructura el código, cómo nombra variables y funciones, cómo segrega responsabilidades, cuándo decide dejar de anidar condiciones, qué estructuras de datos prefiere, cómo le gusta procesar colecciones de datos, sus inclinaciones dentro de los paradigmas de programación…</p> <p>El estilo de cada programador/a se parece a una especie de caligrafía, un acento al hablar o una colección de muletillas e incluso de palabrotas. No es algo que deba importar en la industria, pero sí es algo que, a veces, aparece. Y quería hablar de ello, porque desde fuera, parece que el código está libre de la humanidad de sus programadores; y no hay nada más lejos de la realidad. En la era de los LLMs, esto está cambiando; y no hago un juicio de valor, pero sí hay algo quería visibilizar. Muchas actividades humanas, aunque se deleguen en muchos casos o se automaticen para el consumo, no van a desaparecer de la vida de quienes las practican, por el simple hecho de que son inherentemente humanas; y <strong>como tecnólogo, siempre me ha parecido que programar es una de esas actividades</strong>.</p>]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[Una perspectiva poco compartida sobre la naturaleza del código es lo que se puede saber de una persona por su manera de escribirlo. Algo así tenía en mente cuando escribí sobre la programación como conversación, pero en aquel entonces no había leído tanto código escrito por IA. No voy a entrar en cuestiones como la productividad, la calidad del código ni métricas software o buenas prácticas; estas incumben a la industria, y ahora quiero hablar de la programación como actividad humana.]]></summary></entry><entry><title type="html">Human code</title><link href="/blog/human-code" rel="alternate" type="text/html" title="Human code"/><published>2025-12-24T00:00:00+01:00</published><updated>2025-12-24T00:00:00+01:00</updated><id>/blog/human-code</id><content type="html" xml:base="/blog/human-code"><![CDATA[<p>A little-shared perspective on the nature of code is what you can learn about a person from the way they write it. I had something like this in mind when I wrote about <a href="https://miguelmj.dev/blog/programming-as-a-conversation-how-the-communicative-scheme-is-also-applied-in-the-written-code-itself">Programming as Conversation</a>, but at that time I hadn’t read as much code written by AI. I’m not going to get into issues such as productivity, code quality, software metrics or best practices; these are matters for the industry, and now I want to talk about programming as a human activity.</p> <p><strong>I think I can remember every time I have felt the impression of another person when reading their code</strong>. And I am talking about interacting with code on a daily basis; not reading a file or a pair of functions, but reading, day after day, the lines written by another person; understanding a system they have created. When we talk about narrative texts, poetry, diaries, letters… the presence of the person reaches us through human language, the same language they would use to talk to us on the street. However, in code, the impositions of a formal language and the definition of an algorithm are mixed together. Even so, the programmer’s personality shines through in their knowledge of their tools, their understanding of the problem to be solved, and the way they express these solutions, even when mediated by conventions and standards. Often, <strong>we programmers like the code to have a certain look</strong>, a certain way of reading; this then becomes style conventions, but it starts out as a personal choice pursuing some subjective legibility. Even the absence of this intention builds an identity. It happens to me even when I read my own code, that I feel a reminiscence of how I was when I wrote it; what I was interested in trying out, what techniques I had become proficient in, or what knowledge I did not yet have.</p> <p>That’s why I’ve sometimes felt that <strong>reading code creates a small sense of intimacy</strong>. It’s a little window into how another person’s mind works. When working on team projects, you can recognise the author of pieces of code at a glance without having to ask. And I find this form of knowledge endearing, even when I curse the person who wrote such spaghetti code. Because other times, if it’s good code, the author tells you how to program better; and when it’s not, you get to share the confusion they may have had to endure, or at least empathise with their level of experience, because we all started somewhere.</p> <p>When I am programming a slightly more complex system, I feel like I am holding a small building in my mind, and when I translate it into code, I leave it imprinted on it. Like any creative technical process, it can sometimes feel lonely. And when I read someone else’s code, when I see their choice of architecture, what practices they use and which they don’t, I reconstruct the building that they held in their mind at some point. It’s like putting yourself in their shoes. By doing this many times, you become familiar with their way of working, you recognise how they structure the code, how they name variables and functions, how they segregate responsibilities, when they decide to stop nesting conditions, what data structures they prefer, how they like to process data collections, their inclinations within programming paradigms…</p> <p>Each programmer’s style is like a kind of calligraphy, a speech accent or a collection of catchphrases and even swear words. It’s not something that should matter in the industry, but it is something that sometimes just appears. And I wanted to talk about it, because from the outside, it seems that code is free from the humanity of its programmers; and nothing could be further from the truth. In the era of LLMs, this is changing; and I’m not making a value judgement, but there is something I wanted to highlight. Many human activities, even if they are delegated in many cases or automated for consumption, are not going to disappear from the lives of those who practise them, simply because they are inherently human; and <strong>as a technologist, I have always felt that programming is one of those activities</strong>.</p> <p><small>Translated with Deepl from <a href="./codigo-humano">Código humano</a></small></p>]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[A little-shared perspective on the nature of code is what you can learn about a person from the way they write it. I had something like this in mind when I wrote about Programming as Conversation, but at that time I hadn’t read as much code written by AI. I’m not going to get into issues such as productivity, code quality, software metrics or best practices; these are matters for the industry, and now I want to talk about programming as a human activity.]]></summary></entry><entry><title type="html">Mi actualización de 2025</title><link href="/blog/mi-actualizacion-de-2025" rel="alternate" type="text/html" title="Mi actualización de 2025"/><published>2025-12-08T00:00:00+01:00</published><updated>2025-12-08T00:00:00+01:00</updated><id>/blog/mi-actualizacion-de-2025</id><content type="html" xml:base="/blog/mi-actualizacion-de-2025"><![CDATA[<p>Ha pasado un año desde la última vez que publiqué nada en este blog. La verdad es que pienso a menudo en escribir, en compartir lo último que he aprendido o reflexionar sobre algún tema actual de software o IA (un tema verdaderamente inagotable). Sin embargo, este último año ha sido una etapa especialmente intensa, una de esas de las que sabes que no saldrás siendo la misma persona. Este blog nunca ha sido especialmente biográfico, y esta publicación no pretende serlo, pero tal vez sea, en la línea que deje abierta hace un año, un poco más personal. También me apetece escribir en español por la misma razón.</p> <p>De entre los distintos motivos por los que he estado tan disperso este año, está el máster en desarrollo software e IA que estoy cursando en la UMA. El TFM me está sirviendo para aprender mucho sobre algoritmos que no habría tenido excusa de investigar en otro contexto, además de interiorizar, mejor que en el grado, el modo de trabajo propio de la producción científica. Aparte de ello, he terminado un proceso de saltar entre proyectos incompletos de videojuegos hechos en Godot para aterrizar en uno que finalmente tengo perspectivas de completar; ha sido el que más lejos ha llegado, en el sentido de que he publicado una demo en itch.io; y aun con mis otras ocupaciones, tengo la motivación suficiente para cerrar una versión definitiva, e incluso moverlo, si cabe, en el activo mundillo indie de Málaga. Todo esto, junto con otras cuestiones personales, me mantienen alejado de otros hábitos como escribir en mi página web o mantener mis proyectos de código abierto. A pesar del desinterés que puede aparentar la inactividad online (en esta era más que nunca), sigo teniendo muy presentes los textos por completar y los repositorios FOSS por actualizar (especial énfasis en Candle, Milua y Unofficial Openmath).</p> <p>Lo que espero y deseo para este año que viene es cerrar satisfactoriamente estos dos proyectos (el TFM y el videojuego), para volver a estos viejos hábitos que están en pausa; e incorporar a estos un nivel creciente de <em>seniority</em>, que intento construir no sólo en el ámbito laboral, sino en todas las áreas de aplicación de mis valores sobre la tecnología. Todo ello, en parte, inspirado por pertenecer al lado humano de Internet.</p> <p>¡Feliz año!</p>]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[Ha pasado un año desde la última vez que publiqué nada en este blog. La verdad es que pienso a menudo en escribir, en compartir lo último que he aprendido o reflexionar sobre algún tema actual de software o IA (un tema verdaderamente inagotable). Sin embargo, este último año ha sido una etapa especialmente intensa, una de esas de las que sabes que no saldrás siendo la misma persona. Este blog nunca ha sido especialmente biográfico, y esta publicación no pretende serlo, pero tal vez sea, en la línea que deje abierta hace un año, un poco más personal. También me apetece escribir en español por la misma razón.]]></summary></entry><entry><title type="html">Rethinking my online presence</title><link href="/blog/rethiniking-my-online-presence" rel="alternate" type="text/html" title="Rethinking my online presence"/><published>2024-12-09T00:00:00+01:00</published><updated>2024-12-09T00:00:00+01:00</updated><id>/blog/rethiniking-my-online-presence</id><content type="html" xml:base="/blog/rethiniking-my-online-presence"><![CDATA[<h2 id="the-blog-until-now">The blog until now</h2> <p>Soon, almost two years ago, I published a short <a href="/blog/my-blogging-journey-until-now-i-m-moving-to-hashnode">summary of my experience writing this blog</a>, with the idea that switching platforms would help me find an audience that connected better with me. What changed, however, was more my own attitude towards the activity of writing.</p> <p>In these two years I have only written three blog posts (the period when I wrote weekly is long gone) and that has allowed me to focus on other more elaborate texts that had been on the back burner for some time. Unlike these publications, these texts have been written in Spanish and have taken me several weeks or months each, with a very small and close audience in mind. By separating them from my usual publications and writing them for myself, I have also been able to perceive my writing with a new perspective. I have realised that different needs require different texts, and that part of the identity crisis of my blog so far came precisely from not being clear about its specific purpose.</p> <p>Looking back over my past posts, I realised that sometimes I wanted to share my latest learnings, sometimes I wanted to produce content to serve as teaching material, often I wrote about ideas I wish I had received in my early stages of engineering education, and lately I was trying to explore new ways of presenting my more personal interests. My intention from now on is to separate these needs so that the blog serves a more relatable and contextualised type of text (what a blog traditionally is).</p> <p>On the other hand, I have had to come to terms with the fact that I can’t write everything in English. I think more clearly in Spanish and will most likely switch to writing in both languages, depending on what I write and when I write it. I still plan to try automatic translation of posts, though (this one has been translated automatically, for example).</p> <h2 id="the-blog-and-my-website">The blog and my website</h2> <p>As I said in that post, I was trying to build a minimal online presence to compensate for the lack of work experience before I graduated. Predictably, this recent years of employement have changed that intention. I’m not sure if that presence was ever of any use, but what is clear to me is that that purpose is no longer what I want for my blog or, in general, for my website. I now intend to put it to a more complete and personal use. Moreover, having learned about the concept of POSSE I also want to make it the central node of my web presence. This, together with a new revamp of the site, which includes a new migration of the blog to self-hosting, constitutes my new way of approaching my online presence. The revamp also includes a new section where I’ll keep these other texts I mentioned earlier.</p> <p>With a relaxed attitude towards what I write, I know I will enjoy running this blog more, focusing less on making myself employable or gaining an audience, and more on building a record of what I learn and what I want to share.</p> ]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[The blog until now]]></summary></entry><entry><title type="html">Programming as a conversation</title><link href="/blog/programming-as-a-conversation-how-the-communicative-scheme-is-also-applied-in-the-written-code-itself" rel="alternate" type="text/html" title="Programming as a conversation"/><published>2024-05-11T00:00:00+02:00</published><updated>2024-05-11T00:00:00+02:00</updated><id>/blog/programming-as-a-conversation-how-the-communicative-scheme-is-also-applied-in-the-written-code-itself</id><content type="html" xml:base="/blog/programming-as-a-conversation-how-the-communicative-scheme-is-also-applied-in-the-written-code-itself"><![CDATA[<p>Coding conventions, documentation practices and nomenclature styles are commonly subject of strong opinions among developers. In my case, I really thought for years that the best way to write software had to exist, even if it was not mine. And, surely, there are objective criteria that make code better, from the best use of idioms to the readability-performance tradeoffs. However, I’ve come to think that <strong>understanding code as a conversation where subjectivity takes a role</strong> might be the most valuable approach to write software, rather than one that assumes universal metrics.</p> <h2 id="introduction---programming-as-talking-to-a-machine">Introduction - Programming as talking to a machine</h2> <p>When I was learning to program, my university teachers used to present programming as a way to communicate with a computer. Compilers are translators between high level programming languages (closer to human languages) and machine language, binary encoded in metal circuits; therefore, <strong>to program is to talk with a computer</strong>. Obviously, this definition is not wrong, but in the software development industry context, it is clearly reductionist, as it ignores many other factors involved in development. However, this is precisely the approach that most academics I’ve worked with take, deliberately or not.</p> <h2 id="academy-and-industry">Academy and industry</h2> <p>The reason for this difference between industry and academy is the fundamental understanding of what programming is and, as a consequence, what life cycle of software is.</p> <p><strong>In the academy, programming is a tool to build systems that model a theoretical problem, that solve particular tasks, that embody specific demonstrations or proofs</strong>. Projects evolve from simple scripts to bigger systems, usually written collaboratively between professors, doctoral candidates and inexperienced, unsupervised, recently graduated students, neither of whom uses to care much about long term maintainability. This, along with a general lack of supervision, results in partial or absolute absence of tests, absence of style conventions, inconsistent coupling levels across the architecture and other usually considered bad consequences.</p> <p>On the other hand, <strong>industry software development takes programming as a tool to build products that need to meet requisites set by clients and changing markets</strong>. Projects might last for many years and will be developed, extended, refactored and maintained by very different developers over the course of time. In the industry, this software is alive and evolving. Therefore, its architecture must be able to adapt and grow by the hand of whole teams that may also change over time.</p> <p>For this reason, projects that come from the academy to find a place in the market will eventually face a complete readjustment if they want to survive. However, not all software is meant to end up in the market. Not all projects are born to live long lives, to be built collaboratively or to evolve at some point. If a piece of software works and no one is meant to ever touch it again, apart from maybe the original creator, then complex architectures, coding conventions and best-practices can be an unnecessary overhead. <strong>It is very important to identify the expected cycle of life for a program</strong>, to be objective about how it will need to be maintained.</p> <h2 id="programming-as-a-dialogue">Programming as a dialogue</h2> <p>The first time I was told my code sucked was in an issue on one of my open source projects, where the developer in question told me, with no offense intended, that the unreadable code made it hard to contribute. I always tried to make my code readable, how could someone not understand it? So I went to the mentioned piece of code and, what a shame, it was ten times more unreadable than I remembered: obscure variable names, deep levels of nesting in control structures, walls of code without either comments or subroutine division… Basically, they were right.</p> <p>I didn’t take time to improve it. In the end, it’s an open source library used by very few people and contributed by even less, and I had better things to do. But a year or two later, I landed a new job and my new co-worker told me, during my first code review: <strong><em>“You are not used to writing code in a team, right?”.</em></strong> Since he had seen I was willing to learn, he had a very good attitude towards me and showed me the clean code practices that the team followed. However, that particular question stuck with me. It was not my first job, but it was, indeed, the first time I was going to write code, on which my income would depend, that other people would be working with.</p> <p>I came to the realization that, when I wrote code without supervision (for personal projects or in a solo team) my inner discourse would go on like a <strong>monologue</strong>. As I internalized at university, I was just talking to the computer. After that code review and more that came after, I was required to have an inner discourse that worked as a <strong>dialogue</strong>. I had to talk to the machine but also to my teammates. But, how is that done through code?</p> <h2 id="langue-vs-parole">Langue vs Parole</h2> <p>In linguistics, there’s a difference between <em>langue</em> and <em>parole</em>. The first one is the common code use to communicate with others (the language), and the second one is the particular way it’s used by an individual. For this difference, if you happen to be in the bus and listen to a conversation between two close friends, you might hear a lot of things that you don’t understand, even though they are speaking the same language as you. Not only because you may lack context, but because (oversimplifying) their specific use of language might be alien to you. The same happens with code.</p> <p>If you alone are communicating with the computer, there is no problem to write code as a monologue. As far as I know, this is pretty frequent, for example, in indie game development. Some great indie games, like Undertale, are said to have terrible codebases. Given that many indie developers learn to code during the development of the game itself, it is not something strange. But, in the end, it doesn’t matter at all. <strong>The game is finished, machines run it and people play it.</strong> <strong>There would be absolutely no point in rewriting the game only for it to follow industry best-practices</strong>. The same happens with <em>some</em> university projects. Once you have processed a dataset and extracted what you needed, or once you have tested the algorithm you were developing, a new architecture won’t make any improvement on your desired results.</p> <p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1cx0whguo9hafnxy2pt.png" alt="Diagram of a developer, software and a computer"/></p> <p>However, if you work in a team and follow this “monologue approach”, you will end up with <strong>serious</strong> problems. And when I say team, I also mean open source contributors or future maintainers for solo projects. Interpret it in a broad sense. The codebase receives input from several channels that, the same way as in the bus example, exclude others from the conversation. <strong>Your teammates will need to understand the language and your use of it to comprehend the code</strong>. This will be aggravated with each new contributor that joins the project.</p> <p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0rfppmwz5rwy7q0vsq6c.png" alt="Diagram of a team of developers, software and a computer"/></p> <p>To avoid that, conventions are needed. Because, let’s be real: even the most self-explanatory code can reach a point of complexity that require outside explanations, at the very least for inexperienced members of the team. Every developer that says otherwise is just assuming a level of experience and knowledge of industry standards that not everybody (starting with me) has reached yet. So, the conventions must include design patterns, code styling, nomenclature and even testing philosophy. <strong>Choosing the conventions that adjust the best to both the project requirements and the used technologies, and effectively communicating them to the other developers (usually via documentation or onboarding processes), can make the definitive difference for a project in the long term.</strong></p> <p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n9j3vcm47nbro21ahk9k.png" alt="Diagram of a team of developers, conventions, software and a computer"/></p> <p>Needless to say, it is not all about choosing the perfect conventions, that, to start with, don’t exist. Unclear or changing requirements, too simple or too complex architectures, and many other factors are also determinants of this long term maintainability. Again, software development is a complex activity with many factors involved.</p> <h2 id="conclusion---ensuring-conventions">Conclusion - Ensuring conventions</h2> <p>As in any form of communication, the code conventions chosen for a team and a project may be sometimes interpreted in different ways or with varying levels of rigor by each programmer. Subjectivity is like that. Therefore, <strong>code reviews become an inseparable part of the said conventions’ proper application</strong>. What is legible for you may (and will) not be legible for others. So having more eyes on the code is a good way to make it more accessible. Both giving and receiving feedback on written code must be handled with humanity and an open mind.</p>]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[Coding conventions, documentation practices and nomenclature styles are commonly subject of strong opinions among developers. In my case, I really thought for years that the best way to write software had to exist, even if it was not mine. And, surely, there are objective criteria that make code better, from the best use of idioms to the readability-performance tradeoffs. However, I’ve come to think that understanding code as a conversation where subjectivity takes a role might be the most valuable approach to write software, rather than one that assumes universal metrics.]]></summary></entry><entry><title type="html">When numbers don’t make sense</title><link href="/blog/when-numbers-don-t-make-sense" rel="alternate" type="text/html" title="When numbers don’t make sense"/><published>2023-03-09T00:00:00+01:00</published><updated>2023-03-09T00:00:00+01:00</updated><id>/blog/when-numbers-don-t-make-sense</id><content type="html" xml:base="/blog/when-numbers-don-t-make-sense"><![CDATA[<h2 id="introduction">Introduction</h2> <p>Most of the time, basic arithmetic is pretty simple and intuitive. Even working with powers and roots isn’t that much of a headache. However, the IEEE standard for floating-point numbers includes special values that can mess things up: NaN (Not a Number), positive infinity and negative infinity. In fact, most algebraic properties of real numbers are no longer valid. The only purpose of this post is to show some cases I found interesting, where these values produce counterintuitive results.</p> <blockquote> <p>Cover image by <a href="https://unsplash.com/@armand_khoury">Armand Khoury</a> from Unsplash</p> </blockquote> <h2 id="standard-behavior-of-nan-and-infinity">Standard behavior of NaN and Infinity</h2> <ul> <li> <p>For all x: <code class="language-plaintext highlighter-rouge">NaN &gt; x</code> is false.</p> </li> <li> <p>For all x: <code class="language-plaintext highlighter-rouge">NaN &lt; x</code> is false.</p> </li> <li> <p>For all x: <code class="language-plaintext highlighter-rouge">NaN == x</code> is false.</p> </li> <li> <p>For all x: <code class="language-plaintext highlighter-rouge">NaN != x</code> is true.</p> </li> <li> <p>For all x except NaN and +Infinity: <code class="language-plaintext highlighter-rouge">+Infinity &gt; x</code> is true.</p> </li> <li> <p>For all x except Nan and -Infinity: <code class="language-plaintext highlighter-rouge">-Infinity &lt; x</code> is true.</p> </li> <li> <p><code class="language-plaintext highlighter-rouge">Infinity / Infinity = NaN</code></p> </li> <li> <p><code class="language-plaintext highlighter-rouge">Infinity * 0 == NaN</code></p> </li> <li> <p><code class="language-plaintext highlighter-rouge">Infinity - Infinity == NaN</code></p> </li> <li> <p>Any other arithmetic operation between a number and Infinity results in Infinity (with a possible change of sign).</p> </li> <li> <p>Any other arithmetic operation between a number (or Infinity) and NaN results in NaN.</p> </li> </ul> <p>Everything I will tell you from now is trivially deduced from understanding the list above; in other words, if you understand all its implications, I won’t tell you much new. Anyway, I think it is interesting to review some side effects that may escape from us when we don’t keep them in mind.</p> <h2 id="broken-properties">Broken properties</h2> <p>The following is a non-exhaustive list of properties that we use to expect while programming, but are no longer true due to the existence of NaN and Infinity. I will provide the statement of the property (which doesn’t hold) and then a piece of code in JavaScript and Python that implements a check for it, followed by a call that returns false.</p> <p><em>Note</em>: JavaScript produces <code class="language-plaintext highlighter-rouge">NaN</code> and <code class="language-plaintext highlighter-rouge">Infinity</code> values easily, not only because they are native values but because they result from regular operations (<code class="language-plaintext highlighter-rouge">Math.sqrt(-1)</code> or <code class="language-plaintext highlighter-rouge">1/0</code>). In the case of Python, they are implemented in the <code class="language-plaintext highlighter-rouge">math</code> library (<code class="language-plaintext highlighter-rouge">math.nan</code> and <code class="language-plaintext highlighter-rouge">math.inf</code>) and operations that would produce them (<code class="language-plaintext highlighter-rouge">math.sqrt(-1)</code> or <code class="language-plaintext highlighter-rouge">1/0</code>) will raise an exception. For this reason, assume the following header in each Python snippet.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">math</span> <span class="kn">import</span> <span class="n">nan</span><span class="p">,</span> <span class="n">inf</span>
</code></pre></div></div> <p><em>Disclaimer</em>: The snippets of JavaScript will also fail with values like strings or objects. I’m not trying to make any point about errors in JavaScript. The point is about the NaN and Infinity values, which belong to numeric types in any language with full support for the IEEE standard.</p> <hr/> <p>Now, behold the fall of the tautologies.</p> <h3 id="identity">Identity</h3> <p>Let’s start with the most obvious and painful.</p> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">identity</span><span class="p">(</span><span class="nx">x</span><span class="p">){</span>
    <span class="k">return</span> <span class="nx">x</span> <span class="o">==</span> <span class="nx">x</span>
<span class="p">}</span>
<span class="nf">identity</span><span class="p">(</span><span class="kc">NaN</span><span class="p">)</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">identity</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">x</span> <span class="o">==</span> <span class="n">x</span>

<span class="nf">identity</span><span class="p">(</span><span class="n">nan</span><span class="p">)</span>
</code></pre></div></div> <p>Some of the following are direct results of this.</p> <h3 id="a-list-cant-contain-elements-that-arent-equal-to-any-element">A list can’t contain elements that aren’t equal to any element</h3> <p>Sorry for the apparent redundancy in the statement: check the examples to see what I mean.</p> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">checkIncludesEqual</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span> <span class="nx">x</span><span class="p">){</span>
    <span class="k">if</span><span class="p">(</span><span class="nx">arr</span><span class="p">.</span><span class="nf">includes</span><span class="p">(</span><span class="nx">x</span><span class="p">)){</span>
        <span class="k">return</span> <span class="nx">arr</span><span class="p">.</span><span class="nf">some</span><span class="p">(</span><span class="nx">e</span> <span class="o">=&gt;</span> <span class="nx">e</span> <span class="o">==</span> <span class="nx">x</span><span class="p">)</span>
    <span class="p">}</span><span class="k">else</span><span class="p">{</span>
        <span class="k">return</span> <span class="kc">true</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nf">checkIncludesEqual</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="kc">NaN</span><span class="p">],</span> <span class="kc">NaN</span><span class="p">)</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">checkIncludesEqual</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">arr</span><span class="p">:</span>
        <span class="k">return</span> <span class="nf">any</span><span class="p">(</span><span class="n">x</span> <span class="o">==</span> <span class="n">e</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">arr</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">True</span>

<span class="nf">checkIncludesEqual</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">nan</span><span class="p">],</span> <span class="n">nan</span><span class="p">)</span>
</code></pre></div></div> <h3 id="the-max-value-of-a-list-is-greater-than-or-equal-to-the-rest">The max value of a list is greater than or equal to the rest</h3> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">checkMaxIsGE</span><span class="p">(</span><span class="nx">arr</span><span class="p">){</span>
    <span class="kd">let</span> <span class="nx">maxVal</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">max</span><span class="p">(...</span><span class="nx">arr</span><span class="p">)</span>
    <span class="k">return</span> <span class="nx">arr</span><span class="p">.</span><span class="nf">every</span><span class="p">(</span><span class="nx">x</span> <span class="o">=&gt;</span> <span class="nx">maxVal</span> <span class="o">&gt;=</span> <span class="nx">x</span><span class="p">)</span>
<span class="p">}</span>
<span class="nf">checkMaxIsGE</span><span class="p">([</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="kc">NaN</span><span class="p">])</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">checkMaxIsGE</span><span class="p">(</span><span class="n">arr</span><span class="p">):</span>
    <span class="n">maxVal</span> <span class="o">=</span> <span class="nf">max</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
    <span class="k">return</span> <span class="nf">all</span><span class="p">(</span><span class="n">maxVal</span> <span class="o">&gt;=</span> <span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">arr</span><span class="p">)</span>

<span class="nf">checkMaxIsGE</span><span class="p">([</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">nan</span><span class="p">])</span>
</code></pre></div></div> <h3 id="the-min-value-of-a-list-is-lesser-than-or-equal-to-the-rest">The min value of a list is lesser than or equal to the rest</h3> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">checkMinIsLE</span><span class="p">(</span><span class="nx">arr</span><span class="p">){</span>
    <span class="kd">let</span> <span class="nx">minVal</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">min</span><span class="p">(...</span><span class="nx">arr</span><span class="p">)</span>
    <span class="k">return</span> <span class="nx">arr</span><span class="p">.</span><span class="nf">every</span><span class="p">(</span><span class="nx">x</span> <span class="o">&lt;=</span> <span class="nx">minVal</span> <span class="o">&gt;=</span> <span class="nx">x</span><span class="p">)</span>
<span class="p">}</span>
<span class="nf">checkMinIsLE</span><span class="p">([</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="kc">NaN</span><span class="p">])</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">checkMinIsLE</span><span class="p">(</span><span class="n">arr</span><span class="p">):</span>
    <span class="n">minVal</span> <span class="o">=</span> <span class="nf">min</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
    <span class="k">return</span> <span class="nf">all</span><span class="p">(</span><span class="n">minVal</span> <span class="o">&lt;=</span> <span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">arr</span><span class="p">)</span>

<span class="nf">checkMinIsLE</span><span class="p">([</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">nan</span><span class="p">])</span>
</code></pre></div></div> <h3 id="dividend-equals-divisor-times-quotient">Dividend equals divisor times quotient</h3> <p>This is the first we learn about division. <code class="language-plaintext highlighter-rouge">D / d = Q</code> implies <code class="language-plaintext highlighter-rouge">D = Q * d</code>. Well… no more. This example can only be shown in JavaScript because Python prevents division by zero.</p> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">checkDdQ</span><span class="p">(</span><span class="nx">dividend</span><span class="p">,</span> <span class="nx">divisor</span><span class="p">){</span>
    <span class="nx">quotient</span> <span class="o">=</span> <span class="nx">dividend</span> <span class="o">/</span> <span class="nx">divisor</span>
    <span class="k">return</span> <span class="nx">dividend</span> <span class="o">==</span> <span class="nx">quotient</span> <span class="o">*</span> <span class="nx">divisor</span>
<span class="p">}</span>
<span class="nf">checkDdQ</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="nf">checkDdQ</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="kc">Infinity</span><span class="p">)</span>
</code></pre></div></div> <h3 id="the-square-of-a-value-is-either-greater-than-or-equal-to-itself-or-less-than-one">The square of a value is either greater than or equal to itself or less than one</h3> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">checkSquareIsGE</span><span class="p">(</span><span class="nx">x</span><span class="p">){</span>
    <span class="k">return</span> <span class="nx">x</span><span class="o">*</span><span class="nx">x</span> <span class="o">&gt;=</span> <span class="nx">x</span> <span class="o">||</span>  <span class="nx">x</span><span class="o">*</span><span class="nx">x</span> <span class="o">&lt;</span> <span class="mi">1</span>
<span class="p">}</span>
<span class="nf">checkSquareIsGE</span><span class="p">(</span><span class="kc">NaN</span><span class="p">)</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">checkSquareIsGE</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">x</span><span class="o">*</span><span class="n">x</span> <span class="o">&gt;=</span> <span class="n">x</span> <span class="o">||</span> <span class="n">x</span><span class="o">*</span><span class="n">x</span> <span class="o">&lt;</span> <span class="mi">1</span>

<span class="nf">checkSquareIsGE</span><span class="p">(</span><span class="n">nan</span><span class="p">)</span>
<span class="nf">checkSquareIsGE</span><span class="p">(</span><span class="n">inf</span><span class="p">)</span>
</code></pre></div></div> <h3 id="less-than-or-equal-to-is-equivalent-to-not-greater-than">“Less than or equal to” is equivalent to “Not greater than”</h3> <p>I find this particularly disturbing, not sure why.</p> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">checkLEQisNGT</span><span class="p">(</span><span class="nx">x</span><span class="p">){</span>
    <span class="k">return </span><span class="p">(</span><span class="nx">x</span> <span class="o">&lt;=</span> <span class="mi">10</span><span class="p">)</span> <span class="o">==</span> <span class="o">!</span><span class="p">(</span><span class="nx">x</span> <span class="o">&gt;</span> <span class="mi">10</span><span class="p">)</span>
<span class="p">}</span>
<span class="nf">checkLEQisNGT</span><span class="p">(</span><span class="kc">NaN</span><span class="p">)</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">checkLEQisNGT</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">x</span> <span class="o">&lt;=</span> <span class="mi">10</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mi">10</span>

<span class="nf">checkLEQisNGT</span><span class="p">(</span><span class="n">nan</span><span class="p">)</span>
</code></pre></div></div> <h3 id="a-value-divided-by-itself-equals-one">A value divided by itself equals one</h3> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">checkBetweenSelfIsOne</span><span class="p">(</span><span class="nx">x</span><span class="p">){</span>
    <span class="k">return</span> <span class="nx">x</span><span class="o">/</span><span class="nx">x</span> <span class="o">==</span> <span class="mi">1</span>
<span class="p">}</span>
<span class="nf">checkBetweenSelfIsOne</span><span class="p">(</span><span class="kc">NaN</span><span class="p">)</span>
<span class="nf">checkBetweenSelfIsOne</span><span class="p">(</span><span class="kc">Infinity</span><span class="p">)</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">checkBetweenSelfIsOne</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">x</span><span class="o">/</span><span class="n">x</span> <span class="o">==</span> <span class="mi">1</span>

<span class="nf">checkBetweenSelfIsOne</span><span class="p">(</span><span class="n">nan</span><span class="p">)</span>
<span class="nf">checkBetweenSelfIsOne</span><span class="p">(</span><span class="n">inf</span><span class="p">)</span>
</code></pre></div></div> <h3 id="a-value-minus-itself-equals-zero">A value minus itself equals zero</h3> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">checkMinusSelfIsZero</span><span class="p">(</span><span class="nx">x</span><span class="p">){</span>
    <span class="k">return</span> <span class="nx">x</span><span class="o">-</span><span class="nx">x</span> <span class="o">==</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="nf">checkMinusSelfIsZero</span><span class="p">(</span><span class="kc">NaN</span><span class="p">)</span>
<span class="nf">checkMinusSelfIsZero</span><span class="p">(</span><span class="kc">Infinity</span><span class="p">)</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">checkMinusSelfIsZero</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">x</span><span class="o">-</span><span class="n">x</span> <span class="o">==</span> <span class="mi">0</span>

<span class="nf">checkMinusSelfIsZero</span><span class="p">(</span><span class="n">nan</span><span class="p">)</span>
<span class="nf">checkMinusSelfIsZero</span><span class="p">(</span><span class="n">inf</span><span class="p">)</span>
</code></pre></div></div> <h3 id="a-value-times-zero-equals-zero">A value times zero equals zero</h3> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">checkTimesZero</span><span class="p">(</span><span class="nx">x</span><span class="p">):</span>
    <span class="k">return</span> <span class="nx">x</span> <span class="o">*</span> <span class="mi">0</span> <span class="o">==</span> <span class="mi">0</span>

<span class="nf">checkTimesZero</span><span class="p">(</span><span class="kc">NaN</span><span class="p">)</span>
<span class="nf">checkTimesZero</span><span class="p">(</span><span class="kc">Infinity</span><span class="p">)</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">checkTimesZero</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">0</span> <span class="o">==</span> <span class="mi">0</span>

<span class="nf">checkTimesZero</span><span class="p">(</span><span class="n">nan</span><span class="p">)</span>
<span class="nf">checkTimesZero</span><span class="p">(</span><span class="n">inf</span><span class="p">)</span>
</code></pre></div></div> <hr/> <p>These last two have an interesting side effect too. One would expect that <code class="language-plaintext highlighter-rouge">1 / (x-x)</code> and <code class="language-plaintext highlighter-rouge">1 / (x * 0)</code> to result in Infinity. However, when <code class="language-plaintext highlighter-rouge">x</code> is Infinity, they result in NaN. Don’t you feel dizzy yet?</p> <h2 id="bonus-fun-fact">Bonus fun fact!</h2> <p>Hey, while working on this article I found something interesting about square roots in Python. As I stated earlier, Python raises an exception if you try to compute the square root of a negative number. But <a href="https://realpython.com/python-complex-numbers/">Python implements complex numbers</a> natively so if you use the power operator (<code class="language-plaintext highlighter-rouge">**</code>) instead, it returns a valid result!</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="n">math</span> <span class="kn">import</span> <span class="n">sqrt</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nf">sqrt</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="nc">Traceback </span><span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
  <span class="n">File</span> <span class="sh">"</span><span class="s">&lt;stdin&gt;</span><span class="sh">"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1</span><span class="p">,</span> <span class="ow">in</span> <span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span>
<span class="nb">ValueError</span><span class="p">:</span> <span class="n">math</span> <span class="n">domain</span> <span class="n">error</span>
<span class="o">&gt;&gt;&gt;</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">**</span> <span class="mf">0.5</span>
<span class="p">(</span><span class="mf">6.123233995736766e-17</span><span class="o">+</span><span class="mf">1j</span><span class="p">)</span>
</code></pre></div></div> <p>The perfect result would have been <code class="language-plaintext highlighter-rouge">(0+1j)</code> but due to floating-point precision issues, instead of <code class="language-plaintext highlighter-rouge">0</code> you have a very, very small number. I hope you found it interesting too!</p> <h2 id="conclusion">Conclusion</h2> <p>Semantically sound code is much less prone to errors and reduces the need to be constantly catching exceptions. I hope these examples have served as a reminder that we cannot neglect special numeric values or take for granted many seemingly intuitive properties that, if overlooked, can cause apparently correct code to exhibit undesired behavior.</p>]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[Introduction]]></summary></entry><entry><title type="html">Programming mathematical objects</title><link href="/blog/programming-mathematical-objects" rel="alternate" type="text/html" title="Programming mathematical objects"/><published>2023-01-26T00:00:00+01:00</published><updated>2023-01-26T00:00:00+01:00</updated><id>/blog/programming-mathematical-objects</id><content type="html" xml:base="/blog/programming-mathematical-objects"><![CDATA[<h2 id="introduction">Introduction</h2> <p>This post is divided into two main parts. In the first one, I’m going to introduce mathematical objects and mathematical applications. It is programmer-oriented, but I assume some level of math knowledge. In the second part, I will tell my personal experience discovering and researching previous work on this same topic.</p> <p><em>Note</em>: In case you know it, the <a href="https://www.wolfram.com/language/">Wolfram Language</a> may come to your mind while reading this post. It is probably the most powerful tool out there for programming mathematics, as it is the result of years of continuous work by a very talented team. However, I won’t talk about it here because even though it is <a href="https://blog.wolfram.com/2021/11/30/six-reasons-why-the-wolfram-language-is-like-open-source/">more accessible than I thought at first</a>, it imposes restrictions that I didn’t want to deal with. I was not going to expect my reader to do so if I didn’t, in the first place.</p> <h2 id="what-are-mathematical-objects">What are mathematical objects?</h2> <p>Anything we use to make math is a mathematical object. For example, numbers (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn></mrow><annotation encoding="application/x-tex">3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>27</mn></mrow><annotation encoding="application/x-tex">27</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord">7</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>−</mo><mn>80</mn></mrow><annotation encoding="application/x-tex">-80</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">−</span><span class="mord">8</span><span class="mord">0</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3.15</mn></mrow><annotation encoding="application/x-tex">3.15</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">.</span><span class="mord">1</span><span class="mord">5</span></span></span></span>, …), symbols (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>+</mo></mrow><annotation encoding="application/x-tex">+</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord">+</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>−</mo></mrow><annotation encoding="application/x-tex">-</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord">−</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>=</mo></mrow><annotation encoding="application/x-tex">=</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi></mrow><annotation encoding="application/x-tex">\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">π</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">ϵ</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msqrt><mrow></mrow></msqrt></mrow><annotation encoding="application/x-tex">\sqrt{}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.04em;vertical-align:-0.2395em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8005em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"></span></span><span style="top:-2.7605em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702 c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14 c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54 c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10 s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429 c69,-144,104.5,-217.7,106.5,-221 l0 -0 c5.3,-9.3,12,-14,20,-14 H400000v40H845.2724 s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7 c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z M834 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2395em;"><span></span></span></span></span></span></span></span></span>, …) and variables (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">x</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>y</mi></mrow><annotation encoding="application/x-tex">y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">y</span></span></span></span>, …). From simple mathematical objects, we can build other more complex, like operations (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn><mo>+</mo><mn>5</mn></mrow><annotation encoding="application/x-tex">3+5</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mi>x</mi></msup></mrow><annotation encoding="application/x-tex">2^x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.664392em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">x</span></span></span></span></span></span></span></span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mo>∪</mo><mi>B</mi></mrow><annotation encoding="application/x-tex">A \cup B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∪</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span> …), relationships ( <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mo>&lt;</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">2 \lt 3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68354em;vertical-align:-0.0391em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo mathvariant="normal">≠</mo><mn>10</mn></mrow><annotation encoding="application/x-tex">x \ne 10</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathdefault">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"><span class="mrel"><span class="mord"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.69444em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="rlap"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="inner"><span class="mrel"></span></span><span class="fix"></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.19444em;"><span></span></span></span></span></span></span><span class="mrel">=</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">0</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">1 = 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span> ) and even full theorems ( <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">∀</mi><mi>x</mi><mo separator="true">,</mo><mi>y</mi><mo>∈</mo><mi mathvariant="double-struck">N</mi><mo separator="true">,</mo><mi>x</mi><mo>&lt;</mo><mi>y</mi><mtext>  </mtext><mo>⟺</mo><mtext>  </mtext><mi mathvariant="normal">∃</mi><mi>z</mi><mo>∈</mo><mi mathvariant="double-struck">N</mi><mo>:</mo><mi>x</mi><mo>+</mo><mi>z</mi><mo>=</mo><mi>y</mi></mrow><annotation encoding="application/x-tex">\forall x, y \in \mathbb{N}, x&lt;y \iff \exists z \in \mathbb{N}:x+z=y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord">∀</span><span class="mord mathdefault">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">y</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.88333em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathbb">N</span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.7194400000000001em;vertical-align:-0.19444em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">y</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">⟺</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.73354em;vertical-align:-0.0391em;"></span><span class="mord">∃</span><span class="mord mathdefault" style="margin-right:0.04398em;">z</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68889em;vertical-align:0em;"></span><span class="mord"><span class="mord mathbb">N</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord mathdefault">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.04398em;">z</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">y</span></span></span></span> ).</p> <p>Modern programming languages provide all kinds of interfaces to represent and manipulate mathematical objects. Numbers, for example, are present in any non-esoteric language you will stumble upon. But what about more complex objects?</p> <h2 id="mathematical-objects-in-programming-languages">Mathematical objects in programming languages</h2> <h3 id="mathematical-objects-as-data-structures">Mathematical objects as data structures</h3> <p>While mathematical objects are relatively abstract concepts, their implementation in a computer is directly related to data structures. Different languages define different native data structures, and each compiler/interpreter implements the operations on said data structures, determining the mathematical objects that can be manipulated by that programming language without additional programming.</p> <p>I say “without additional programming” because, in the end, all programming languages (the Turing-complete ones) are equivalent. Since we live in the future, you will find that popular languages have libraries that implement anything you can think of.</p> <h3 id="languages-for-mathematical-applications">Languages for mathematical applications</h3> <p>MatLab works natively with matrices and their operations. Do you want to work with matrices in Python? With NumPy, you can, but it will be a little bit harder than with MatLab. Do you want to work with matrices in C? You also can, but it will be harder than with Python.</p> <p>This is just a crude case of how different languages handle better some mathematical objects. And while matrices are a relatively common thing to use in programming languages, other math concepts are not. Remember that we are talking about very different fields of mathematics. You would be surprised how cleaner or even faster can be a program written in less conventional languages like Haskell or Prolog, depending on the problem.</p> <p>So imagine you need an application capable of handling a lot of different math concepts: arithmetic, algebra, logic, geometry… What are your options as a programmer?</p> <ul> <li> <p>You can choose a single multi-purpose language, like Python, R or Julia, that have immense repositories of libraries of all sorts. You may find redundancies that you would need to contemplate and probably translate to common data structures. Also, some concepts might end up being difficult to use in an idiomatic, clean way. Or, on the contrary, to make them idiomatic, they turn out to be poorly optimized.</p> </li> <li> <p>You could use more than one language and glue them somehow or even embed one into another. This way, you could take advantage of the benefits of each. Have you ever wondered how powerful could be an application made with JavaScript + Python (PyScript) + Prolog (TauProlog)? That sounds like the <a href="https://www.youtube.com/watch?v=-O01G3tSYpU">third wave of AI</a> to me! Just kidding, sounds very interesting but just reading it already gives me a headache.</p> </li> <li> <p>Another option is to turn your application into different distributed services. Collaboration is key to growth, isn’t it? What if we implemented specialized services for different math fields and tasks and then make them talk to each other? It has the advantages of both previous points. You have a modular architecture, you can reuse code and you can use different languages, the most suited for each task.</p> </li> </ul> <h2 id="distributed-math-applications">Distributed math applications</h2> <h3 id="shared-formats-as-middleware">Shared formats as middleware</h3> <p>When you connect several applications, you need formats. We could let each application communicate the way it wanted and enable the main system to interpret every possible format, but that’s not scalable.</p> <p>The Web is the best example of this. Everything you display on a webpage is HTML <strong>by convention</strong>. There are countless markup languages, document formats… but if you want something rendered in your browser, you better translate it to HTML. Look at Mathjax or KaTeX. We didn’t want to write mathematical equations directly in HTML, because LaTeX was better for that. So we made applications that translated it into HTML.</p> <h3 id="formats-for-humans-vs-semantic-formats-for-machines">Formats for humans vs Semantic formats for machines</h3> <p>Standard formats are powerful. When machines are able to communicate, everything is better. But HTML and CSS, for example, are a special case for one reason: their final target are human eyes. An HTML page might be a complete mess, but if it renders into a human-readable page, it’s alright.</p> <p>In fact, when we decided that we wanted the web to be machine-readable, the concept of the <a href="https://en.wikipedia.org/wiki/Semantic_Web">semantic web</a> was born. Because machines do not care about presentation, they care about <strong>semantics</strong>: the meaningful information they can parse from the used formats.</p> <h3 id="semantic-math-formats">Semantic math formats</h3> <p>And here’s the problem with a lot of formats for mathematical object representation; they are made to present information to humans, not to machines. LaTeX, for example, doesn’t hold much semantic information.</p> <p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mi>y</mi><mo>+</mo><mi>s</mi><mi>i</mi><mi>n</mi><mo stretchy="false">(</mo><mi>e</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">xy + sin(e)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7777700000000001em;vertical-align:-0.19444em;"></span><span class="mord mathdefault">x</span><span class="mord mathdefault" style="margin-right:0.03588em;">y</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault">s</span><span class="mord mathdefault">i</span><span class="mord mathdefault">n</span><span class="mopen">(</span><span class="mord mathdefault">e</span><span class="mclose">)</span></span></span></span></p> <p>The expression above is written in valid LaTeX, but it is pretty ambiguous. Is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mi>y</mi></mrow><annotation encoding="application/x-tex">xy</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathdefault">x</span><span class="mord mathdefault" style="margin-right:0.03588em;">y</span></span></span></span> a single variable, or the product of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">x</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>y</mi></mrow><annotation encoding="application/x-tex">y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">y</span></span></span></span>? Is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>e</mi></mrow><annotation encoding="application/x-tex">e</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">e</span></span></span></span> the Euler constant or an independent variable? We don’t know, because LaTeX is not a semantic format. A human would know the answers thanks to the context in which we use the expression, but probably that context is not machine-readable.</p> <p>Wikipedia points out three main <a href="https://en.wikipedia.org/wiki/Mathematical_markup_language">formats for computer interchange</a>: MathML, OpenMath and OMDoc. The people involved in the development of each one worked on the others too, so they are sort of complementary.</p> <ul> <li> <p><a href="https://www.w3.org/TR/MathML3/"><strong>MathML</strong></a> has two variants: Presentation MathML, which doesn’t hold semantic information, and Content MathML, which does. The mechanism for describing the semantics of its symbols is not present in the format itself. For that, it relies on the OpenMath standard (or similar alternatives).</p> </li> <li> <p><a href="https://openmath.org/"><strong>OpenMath</strong></a> provides two encodings to represent mathematical objects and also defines an extensible mechanism to describe the semantics of its symbols: the <strong>Content Dictionaries</strong>. There are official dictionaries that describe various symbols for different fields of mathematics, but any person or organization could define more dictionaries to extend the number of objects representable by the format. This way, an application that uses follows this standard only has to specify which dictionaries it supports.</p> </li> <li> <p><a href="https://www.omdoc.org/"><strong>OMDoc</strong></a>, on the other hand, is some kind of extension to both MathML and OpenMath, designed to represent mathematical documents for humans and machines alike.</p> </li> </ul> <p><em>Note</em>: I shouldn’t finish this section without mentioning the existence of SCSCP (Symbolic Computation Software Composability Protocol). It is a protocol developed to communicate distributed systems for mathematical computation, or CAS (Computer Algebra System). It is built on top of the OpenMath standard to describe a server-client communication oriented to mathematical objects.</p> <h2 id="my-experience-with-the-openmath-standard">My experience with the OpenMath standard</h2> <h3 id="first-encounter---apparent-death">First encounter - Apparent death</h3> <p>OpenMath is the best suited standard to communicate distributed math applications.</p> <p>I was really excited when I found this standard. As long as an application supported the OpenMath encoding (OM), it could be communicated with lots of other interesting applications easily, with a common format. A whole new world of possibilities for collaboration! I was sure I would find applications to transform OM into renderable formats like LaTeX or HTML, reduce or evaluate complex mathematical expressions, transform function definitions into code, etc.</p> <p>However, disappointment came when I continued to research. Reading the openmath.org page I found a list of projects that used the standard. The first time I clicked on one: broken link. But, hey! the next link works! … and the linked project is obsolete; it has unresolved and unfindable dependencies. The official page is <strong>full</strong> of broken links and obsolete, incomplete and undocumented projects.</p> <p>But it did not feel like abandonware from decades ago; there were things dated less than a few years ago. It was the same feeling as being late for a party that had just ended.</p> <h3 id="finding-the-trail">Finding the trail</h3> <p>I only found a <a href="https://github.com/OpenMath/py-openmath">Python library</a> and a <a href="https://lurchmath.github.io/openmath-js/site/">JS package</a> implementing the standard, that seemed to be active to some extent… but neither of them contemplated the full specification.</p> <p>The one in JS is <a href="https://lurchmath.github.io/openmath-js/site/work-done/">a bit basic</a>. And when I tried to use the Python one, I didn’t find it easy to do anything with it apart from parsing and serializing XML; it felt like the mathematical objects were not programmed to be manipulated easily. Of course, that can be (and probably is) my fault, because the library is used in another <a href="https://github.com/OpenMath/py-scscp">SCSCP library</a>, where it proves to be useful.</p> <p>At first, I didn’t give too much attention to the SCSCP library, because I thought it was not related to what I was looking for. I started my own Python implementation of the standard (<em>if you visit it on my GitHub keep in mind it is very unstable and mostly experimental for now</em>) and forgot about any official implementation.</p> <p>However, I recently returned to that library, trying to understand it better with the knowledge acquired by working with OpenMath on my own. The SCSCP library caught my attention this time, and I followed one link after another until I understood what was going on. Part of these projects was recently funded by the EU in a program to foster the development of a European research infrastructure called <a href="https://github.com/OpenDreamKit">OpenDreamKit</a> that happened to finish in 2020. In fact, there are two more projects built on top of both the OpenMath and SCSCP Python libraries that belong to said infrastructure and seem to have little attention from other developers, even though they seem to be the only current functioning projects based on that technologies.</p> <h3 id="my-interpretation">My interpretation</h3> <p><em>Disclaimer</em>: I don’t talk on behalf of anyone except myself and I might have incomplete or wrong information about what’s been going with OpenMath on in the last decades.</p> <p>I’ve spent many hours browsing the pages related to OpenMath and I’ve come to a conclusion. It looks like a lot of this work started long ago, in the nineties, which explains why there is so much that’s become obsolete (so it is in fact like abandonware from decades ago). To me, it looked like back then their work was more similar to projects of software development. But their society has always been closely related to universities and public funds (similar to the OpenDreamKit one). So their current available work is very academic! They have papers instead of documentation and research groups instead of communities.</p> <p>They made their last workshop a year and a half ago (Jul 2021) so they were active recently… But then, why don’t they update their website to reflect the actual state of the project? Why isn’t there any work to integrate the standard into modern, popular frameworks used for mathematics? I’ve come to think that it’s just that, if they are actually still active, I’m out of the appropriate communication channels. I don’t know if I’m in an empty room or just in the wrong room.</p> <h2 id="conclusion">Conclusion</h2> <p>Is the project just close to a death of disinterest? Or maybe the circles using and developing it are <strong>not</strong> the circles of software developers, but of researchers and academics? I honestly don’t know. But, also, I don’t care! I found the project to be fascinating and full of potential. The OM Society might not have the same philosophy as other modern open source projects, but their work is there for us to use it.</p> <p>I think the idea of distributed mathematical systems is <strong>wonderful</strong>. But not only for researchers, who are the people using them right now; <strong>also for developers</strong>! My intention with this post was to make these concepts and possibilities known to people interested in working on open source projects like the ones we do know, in the hope that new, open and active communities can be formed.</p> <hr/> <p><strong>If you liked this topic, let me know and I will write more about it!</strong> ✍🏻 I haven’t explained anything about the format, encodings and content dictionaries of the OpenMath standard, so I’ll probably write another post explaining how to use and implement them.</p> <h2 id="references">References</h2> <ul> <li> <p><a href="https://www.omdoc.org/about/">https://www.omdoc.org/about/</a></p> </li> <li> <p><a href="https://openmath.org/about/">https://openmath.org/about/</a></p> </li> <li> <p><a href="https://www.w3.org/TR/MathML3/">https://www.w3.org/TR/MathML3/</a></p> </li> <li> <p><a href="https://github.com/OpenMath/scscp/blob/master/revisions/SCSCP_1_3.pdf">Symbolic Computation Software Composability Protocol - SCSCP - Specification, Version 1.3</a></p> </li> <li> <p><a href="https://link.springer.com/content/pdf/10.1007/11826095.pdf?pdf=button">OMDoc – An Open Markup Format for Mathematical Documents</a></p> </li> <li> <p><a href="https://github.com/OpenDreamKit/OpenDreamKit/blob/master/WP6/CICM2016/published.pdf">Interoperability in the OpenDreamKit project: the Math-in-the-Middle approach</a> (3rd section)</p> </li> </ul>]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[Introduction]]></summary></entry><entry><title type="html">My blogging journey until now - I’m moving to Hashnode</title><link href="/blog/my-blogging-journey-until-now-i-m-moving-to-hashnode" rel="alternate" type="text/html" title="My blogging journey until now - I’m moving to Hashnode"/><published>2023-01-19T00:00:00+01:00</published><updated>2023-01-19T00:00:00+01:00</updated><id>/blog/my-blogging-journey-until-now-i-m-moving-to-hashnode</id><content type="html" xml:base="/blog/my-blogging-journey-until-now-i-m-moving-to-hashnode"><![CDATA[<h2 id="2020---starting-a-blog">2020 - Starting a blog</h2> <p>It’s been more than two years since I began blogging. It all started with a development journal for one of my latest projects at the second half of 2020. I knew I wouldn’t be graduating that year, so I decided that I could try to gain some online presence to compensate my lack of professional experience.</p> <p>https://dev.to/miguelmj/writing-a-conversational-user-interface-library-full-series-3dc5</p> <p>DEV.to was in a boom, I was seeing a lot of developers start blogs here, so I decided to give it a try. I found the other platforms a bit intimidating, but this one was very approachable and beginner friendly. I wrote every week or two and found some interesting people to follow. I didn’t get much attention, but it didn’t matter! I was here for the experience of writing and the growth that comes along.</p> <p>I wrote more than a development journal. I had a lot of opinions I had formed during my years in university and advice to give, so a lot of what I wrote at that moment was the kind of things I would’ve love to know as a freshman. It was a true pleasure to have a space to write it all down and share it.</p> <p>https://dev.to/miguelmj/why-and-how-to-use-pen-and-paper-design-an-algorithm-11nn</p> <p>Before the year ended, the DEV.to community did <a href="embed https://dev.to/devteam/community-moderation-and-support-on-dev-7me">a lot of work around the moderation</a> of the platform. At that time I was made a trusted member and to say that I found it rewarding, for the short time I had been here, is an understatement.</p> <h2 id="2021---a-comfortable-plateau-and-the-seed-of-dissatisfaction">2021 - A comfortable plateau and the seed of dissatisfaction</h2> <p>With the new year, I slowed down my publication pace and started writing monthly. There was a lot going on in my life, so I felt comfortable with little activity; enough to continue the habit and keep my presence out there. You can tell it was a weird year for me because I have several unfinished series and a failed attempt to translate all my posts to Spanish (my native language).</p> <p>Despite all this, it was a great year in terms of growing my personal brand. My open source projects started to thrive (I was even featured in an <a href="https://makerwork.substack.com/p/makerwork001">incipient newsletter, now dead</a>) and I started writing for my current self, more than for my past self.</p> <p>https://dev.to/miguelmj/data-structures-in-prolog-where-to-start-53gm</p> <p>Also, a very strange episode happened that year.</p> <p>I was invited to write a featured post for another platform. As it was my first post written for someone else, I wanted to make it about a popular topic: JavaScript, something I had never written about before.</p> <p>Unfortunately, that site turned out to be a complete scam. Most of its content is stolen, their complete Q&amp;A section is a literal scrap of the StackOverflow page and each and every user I interacted with was a bot (they even used watermarked stock photos as profile pics).</p> <p>I got out of there as quickly as possible and published my article here in DEV.to. <strong>In less than 24 hours, it had more traffic than all my previous posts together</strong>. Today (January 2023) it is still my third most read post.</p> <p>https://dev.to/miguelmj/take-full-advantage-of-high-order-functions-examples-in-javascript-4ibg</p> <p>I remember reading several posts here talking about the spam, the clickbaity low-effort listicles, the daily copy-pasted git tutorials, etc. If you have been here for a while, you will know that the quality of the DEV.to content is still an unsolved issue. I didn’t fully care, I was comfortable here and that was all that mattered. As a trusted user, I did my best to mark low-quality posts and boost well written, original content.</p> <p>However, dissatisfaction started to grow inside me, and a feeling that something was not fair here. Not only because of all my beloved posts eclipsed by my own single JavaScript tutorial, but also for the people I follow that publish interesting, advanced content, that get 1% of attention and feedback received by the mass of low quality posts focused on beginners.</p> <h2 id="2022---last-year-in-dev">2022 - Last year in DEV</h2> <p>The following year I did very little blogging. Most of my posts in 2022 were for promoting a project or another (looking back, I coded some interesting stuff). The two biggest exceptions were very significant posts to me.</p> <p>https://dev.to/miguelmj/how-to-get-answers-on-stackoverflow-3pp7</p> <p>This one came after I saw some people complaining about the StackOverflow community. I wanted to do an attempt on bringing closer two of the communities I love, from which beginners benefit specially. I expected some backslash in the comments (given the hate SO receives from some people) but instead I got a lot of comments from veteran devs, liking my post. It also gave more insight about who reads what.</p> <p>https://dev.to/miguelmj/javascript-is-not-an-untyped-language-1jkg</p> <p>And then, there’s this one. This one was an explosion. I know it was a controversial opinion on a perma-hot topic like JS, but damn, this post has <strong>five times</strong> as many views as my next most viewed post, and it’s my top reacted and commented post of all time. It got featured in the social networks of DEV, tweeted several times and even improperly published as material for an online course.</p> <p>https://twitter.com/ThePracticalDev/status/1541501371962253314</p> <p>And it was a rant written in a single afternoon! This is perfectly one of the posts I’ve put the least effort into. I stopped writing, discouraged. I know effort doesn’t correlate with impact when we talk about writing on the Internet. But I just didn’t like the idea of going back to write high effort posts for no one, always tempted to write about JavaScript again only for reads.</p> <p>After some time, I was contacted yet by another platform, asking me to write a course for them. Another dev that had worked with them recommended me writing my own book, instead of just a course. Don’t get me wrong, that platform is legit and has great content; in fact, I tried to make the course they wanted. But I didn’t have enough time.</p> <p>Writing an article for a blog is something, but writing a course or a book is another dimension. It is something I want to do, but I probably won’t anytime soon.</p> <h2 id="the-big-hiatus-and-the-decision-to-move">The big hiatus and the decision to move</h2> <p>It’s been months since I published anything. There are several things I want to write about, but these months have been very busy, plus I don’t feel like I have found my audience yet, which disencourages me even more. I don’t even read DEV anymore, as the content quality has only gone down, in spite of the efforts to implement tag filters and experience level for posts.</p> <p>So, to find new motivation, I have decided to move on. I need to keep looking for an audience that I feel I connect with. I <strong>love</strong> DEV and everything I’ve achieved thanks to it, but I need to keep looking for a better space for my blog.</p> <p>I’m going to try my luck with Hashnode. I don’t have any particular reason, so I don’t know if it will be my definitive platform. I want to see what kind of audience I can build there and explore the possibilities of a different tool.</p> <h2 id="conclusion">Conclusion</h2> <p>https://miguelmj.hashnode.dev/</p> <p>My first step has been to migrate there a curated list of my posts and polish them a bit. The canonical URLs will still point to the original posts, nonetheless. I will keep publishing in DEV everything, for the readers I already have here, but I will make Hashnode my main target.</p> <p>I guess that, as a lifelong student and an eventual teacher I will always have something to write for beginners. However, I want to try a different level of writing and even different types of content. I don’t know how my blog might evolve, but, of course, that’s the exciting part!</p>]]></content><author><name></name></author><category term="blog"/><summary type="html"><![CDATA[2020 - Starting a blog]]></summary></entry></feed>