{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Nullable types\n", "\n", "Many object-oriented languages follow the *ALGOL W* example and allow *null references*. Tony Hoare invented the concept in 1965 and since then has called it his \"[my] billion dollar mistake\".\n", "\n", "The follwoing example is destilled from assignment solutions for the lecture *Computergrafik Grundlagen*. \n", "\n", "The `Shape` interface states that a method `intersect()` exists that takes an object of type `Ray` as an argument and returns an object of type `Hit`." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "class Hit {double t;}\n", "class Ray {}\n", "\n", "interface Shape {\n", " Hit intersect(Ray r);\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Concrete instances of `Shape` implement the intersection method differently. For example the `Sphere` class implements it like this:\n", "\n", "```java\n", "class Sphere implements Shape{\n", " public Hit intersect(Ray r) {\n", " if (/* some involved test */)\n", " return new Hit(/* some value for t */);\n", " else\n", " return null;\n", " }\n", "}\n", "```\n", "\n", "Client code of the `Shape` interface has to be prepared, that instead of a valid `Hit` object, `null` is returned to signal the absence of a hit. The interface however, does not explicitly state that this might happen.\n", "\n", "A `NullPointerException` is arguably the most frequently encountered exception in any Java program." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "class Sphere implements Shape{\n", " public Hit intersect(Ray r) {\n", " return null;\n", " }\n", "}" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "No hit\n" ] } ], "source": [ "Ray ray = new Ray();\n", "Sphere sphere = new Sphere();\n", "\n", "Hit hit = sphere.intersect(ray);\n", "\n", "if (hit != null)\n", " System.out.println(hit.t);\n", "else\n", " System.out.println(\"No hit\");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A better solution is to use the `Optional` type that explicitly says *there might be no value* and forces the programmer to check before using a value." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "interface ShapeO {\n", " Optional intersect(Ray r);\n", "}" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "class SphereO implements ShapeO {\n", " public Optional intersect(Ray r) {\n", " return Optional.empty();\n", " }\n", "}" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "ename": "UnresolvedReferenceException", "evalue": "Attempt to use definition snippet with unresolved references in Snippet:ClassKey(SphereO)#21-class SphereO implements ShapeO {\n public Optional intersect(Ray r) {\n return new Optional();\n }\n}", "output_type": "error", "traceback": [] } ], "source": [ "Ray ray = new Ray();\n", "SphereO sphere = new SphereO();\n", "\n", "Optional hit = sphere.intersect(ray);\n", "\n", "if (hit != null)\n", " System.out.println(hit.t);\n", "else\n", " System.out.println(\"No hit\");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] } ], "metadata": { "kernelspec": { "display_name": "Java", "language": "java", "name": "java" }, "language_info": { "codemirror_mode": "java", "file_extension": ".jshell", "mimetype": "text/x-java-source", "name": "Java", "pygments_lexer": "java", "version": "11.0.3+7" } }, "nbformat": 4, "nbformat_minor": 2 }