Does any programming language support defining constraints on primitive data types? - language-agnostic

Last night I was thining that programming languages can have a feature in which we should be able to constraints the values assigned to primitive data types.
For example I should be able to say my variable of type int can only have value between 0 and 100
int<0, 100> progress;
This would then act as a normal integer in all scenarios except the fact that you won't be able to specify values out of the range defined in constraint. The compiler will not compile the code progress=200.
This constraint can be carried over with type information.
Is this possible? Is it done in any programming language? If yes then which language has it and what is this technique called?

It is generally not possible. It makes little sense to use integers without any arithmetic operators. With arithmetic operators you have this:
int<0,100> x, u, v;
...
x = u + v; // is it in range?
If you're willing to do checks at run-time, then yes, several mainstream languages support it, starting with Pascal.

I believe Pascal (and Delphi) offers something similar with subrange types.
I think this is not possible at all in Java and in Ruby (well, in Ruby probably it is possible, but requires some effort). I have no idea about other languages, though.

Ada allows something like what you describe with ranges:
type My_Int is range 1..100;
So if you try assign a value to a My_Int that's less than 1 or greater than 100, Ada will raise the exception Constraint_Error.
Note that I've never used Ada. I've only read about this feature, so do your research before you plunge in.

It is certainly possible. There are many different techniques to do that, but 'dependent types' is the most popular.
The constraints can be even checked statically at compile time by compiler. See, for example, Agda2 and ATS (ats-lang.org).
Weaker forms of your 'range types' are possible without full dependent types, I think.
Some keywords to search for research papers:
- Guarded types
- Refinment types
- Subrange types

Certainly! In case you missed it: C. Do you C? You don't C? You don't count short as a constraint on Integer? Ok, so C only gives you pre-packaged constrained types.
BTW: It seems the answer that Pascal has subrange types misses the point of them. In Pascal array bounds violations are not possible. This is because the array index must of the same type as the array was declared with. In turn this means that to use an integer index you must coerce it down to the subrange, and that is where the run time check is done, not accessing the array.
This is a very important idea because it means a for loop over an array index type may access the array components safely without any run time checking.

Pascal has subranges. Ada extended that a bit, so you can do something like a subrange, or you can create an entirely new type with characteristics of the existing type, but not compatible with it (e.g., even if it was in the right range, you wouldn't be able to assign an Integer to your new type based off of Integer).
C++ doesn't support the idea directly, but is flexible enough that you can implement it if you want to. If you decide to support all the compound assignment operators (+=, -=, *=, etc.) this can be a lot of work though.
Other languages that support operator overloading (e.g., ML and company) can probably support it in much the same way as C++.
Also note that there are a few non-trivial decisions involved in the design. In particular, if the type is used in a way that could/does result in an intermediate result that overflows the specified range, but produces a final result that's within the specified range, what do you want to happen? Depending on your situation, that might be an error, or it might be entirely acceptable, and you'll have to decide which.

I really doubt that you can do that. Afterall these are primitive datatypes, with emphasis on primitive!
adding a constraint will make the type a subclass of its primitive state, thus extending it.
from wikipedia:
a basic type is a data type provided by a programming language as a basic building block. Most languages allow more complicated composite types to be recursively constructed starting from basic types.
a built-in type is a data type for which the programming language provides built-in support.
So personally, even if it is possible i wouldnt do, since its a bad practice. Instead just create an object that returns this type and the constraints (which i am sure you thought of this solution).

SQL has domains, which consist of a base type together with a dynamically-checked constraint. For example, you might define the domain telephone_number as a character string with an appropriate number of digits, valid area code, etc.

Related

Julia: Enforce constraints on objects in a container?

I am rather new to Julia; my programming is typically in C++, Python, or sometimes Fortran for numerics. My understanding is that Julia lacks something analogous to C++'s private variables (or even Python's "I suggest you treat this as private" convention of using a leading underscore). If I have a container, is there a way to enforce constraints on the objects that I add to the container?
Consider an example: Let's say I want an array of integers, and my constraint is that all integers in the array must share a greatest common factor greater than one. So if I put 12 into the array, any number that's a multiple of 2 or 3 may be added. So I next add 21, and the greatest common factor must now be 3. If I try to add 26, I will get an error because it violates the constraint. But had I added 12 then 26, that would be legal with a greatest common factor of 2.
I realize it's a bit of a contrived example, but it should have all the salient features of what I hope to do, and requires less explanation.
True enforcement is only possible for immutable types, where you can check any desired constraints in the inner constructor(s). Outside the type definition there is no way to add new inner constructors, and if there is one you cannot create an instance without going through one.
However, while the convention in Python is that fields that begin with _ are private, the general convention in Julia is that all fields are private (unless they are explicitly documented). It's considered bad style to access fields directly outside the implementation of a type, you should generally have accessor functions instead.

Efficient implementation of multiple return values?

Is it possible to implement efficiently (with little to no runtime overhead) functions that return multiple vales / a tuple type?
In a C-like language something like this:
int, float f(int a) {
return a*2 , a / 2;
}
Is there a reason why very few statically compiled languages do this?
Yes, it can be efficient. You may need to spill registers, but it is possible.
GHC for example, implements the "constructed product return" optimization, that:
determines when a function can profitably return multiple results in registers. The analysis is based only on a function's definition, and not on its uses (so separate compilation is easily supported) and the results of the analysis can be expressed by a transformation of the function definition alone.
CPR is a huge win for returning small structures (i.e. tuples, tagged unions).
More information:
CPR analysis in GHC.
More on demand analysis.
The best paper I have read exactly about this topic is An Efficient Implementation of Multiple Return Values in Scheme (PDF). Although it is about Scheme programming language, they explain the matter in terms of low machine level stack/registry implementation.
This article actually made me think that many high-level features normally considered inefficient are a solved problem regarding the efficient implementation and just the inertia of the popular languages is in the way.
If your tuple doesn't fit into a single register (32- or 64-bit, depending on your architecture, most likely), then there's going to be actual allocation (most likely on the heap) involved in implementing this.
That said, the reasons why very few languages permit this style is unlikely to be related to performance as much as it is likely related to stylistic concerns in the language (i.e., there are other idiomatic ways to achieve the same thing, such as returning a struct). Introducing new primitives to the language can be clumsy and introduce inconsistencies. For example, if tuples become first-class values, can I use them anywhere? How do I access them? Do we enforce immutability? How do I allocate or deallocate them?
Languages with more expressive type systems tend to make it easier to add these kinds of language features in a principled manner, which is why you'll find tuples (and all sorts of other exotic creatures) as first-class values in languages derived from the ML family (amongst others).
In C, just return a struct holding the values. Sure, the result won't fit in a register, unlike an int, so it will not be as efficient as an int return, but it will still be efficient, if the struct is a local variable and thus allocated on the stack rather than the heap.

Haskell storing functions in data structures - use cases

I was going through the Software Foundations book (http://www.cis.upenn.edu/~bcpierce/sf/Basics.html). In the second paragraph of Introduction, it is mentioned that as functions are treated as first class values, they can be stored in a data structure. A quick Google search for the applications of this turned up acid-state (http://acid-state.seize.it/) which probably uses this for storing functions (please correct me if I am wrong). Are there any other applications in which storing functions as data in data structures is/can be used? Is storing functions as data a common pattern in Haskell? Thanks in advance.
Edit: I am aware of the higher order functions.
A simple and easily-used functions-in-data-structure example is that of having a record containing functions (and possibly data).
A good example is in Luke Palmer's blog post Haskell Antipattern: Existential Typeclass where he explains that rather than try to reproduce an OO-like class for widgets, with many instances and then store your UI widgets in an existentially quantified list, you're better off making a record of the actual functions you'll use and returning that instead of retaining your original datatype - once you're existentially quantified, you can't get at the original datatype anyway, so you don't lose anything in expressiveness, but gain a lot in manipulatability. He concludes
Functions are the masters of reuse: when you use an advanced feature, you need a yet more advanced feature to abstract over it (think: classes < existential types < universally quantified constraints < unknown). But all you need to abstract over a function is another function.
This means that we can write higher-order functions to deal with those functions, and pass them around and manipulate them easily, since they're data.
First class functions are extremely useful -- I would contend that their main use case is in higher order functions, which simplify many problems that require more complex patterns in other languages, like Java.

Can a variable like 'int' be considered a primitive/fundamental data structure?

A rough definition of a data structure is that it allows you to store data and apply a set of operations on that data while preserving consistency of data before and after the operation.
However some people insist that a primitive variable like 'int' can also be considered as a data structure. I get that part where it allows you to store data but I guess the operation part is missing. Primitive variables don't have operations attached to them. So I feel that unless you have a set of operations defined and attached to it you cannot call it a data structure. 'int' doesn't have any operation attached to it, it can be operated upon with a set of generic operators.
Please advise if I got something wrong here.
To say that something is structured implies that there is a form or formatting that defines HOW the data is structured. Note this has nothing to do with how the data is actually stored. You could for example create a data structure that exists entirely within a single Integer, yet represents a number of different values.
A data structure is an arbitrary construct used to describe how to store data in a system. It may be as simple as a single primitive, or as complex as a class. So the answer is largely subjective. It's "yes" if you decide to use a primitive as such, that a simple primitive may be considered a primitive data structure, because it describes HOW you wish to store an element of data. The answer is also "no", because it describes an element of a structure and not necessarily the whole structure in itself.
As for how this relates to operations, strictly speaking a data structure has nothing to do with behaviour, it is simply a storage mechanism. Preserving consistency of data is really a behavioural thing. Yes, your compiler probably spits out errors if you try to shoe-horn a 32-bit value into a Byte, but that's symptomatic of the behaviour of the system (Ie: compilation) acting on the data structure of your application, of which your primitives are an element.
I don't think your definition of data structure is correct.
It seems to me that a struct (with no methods) is a valid data structure, but it has no real 'operations'. And that's not important. It's holding data.
To that end, and int holds data, an Object holds data. They are data structures (technically).
That said, I don't ever find myself saying "What datastructure shall I use? I know! an int!".
I would say you need to re-evaluate the meaning of "data structure".
Your definition of a data structure isn't quite correct. A data structure doesn't necessarily have any attached behaviors or operations. An ADT or Abstract Data Type is what you are describing as a data structure. An ADT includes the data and the behaviors or operations that work on that data. An int by itself is not an ADT, but I suppose you could call it a data structure. If you encapsulate an int and its operations then you have an ADT which is what I think you are trying to describe as a data structure. Classes provide a mechanism for implementation of ADTs in modern languages.
wikipedia has a good description of abstract data types.
I would argue that "int" is a data structure - it has a defined representation and meaning. That is, depending on your system, it has a specific length, a specific set of operators available to it, and a specified representation (be it twos-compliment). It is designed to hold "integer numbers".
Practically, the distinction isn't particularly relevant.
Primitives do have operations attached to them; however, they may not be in the format of methods as you would expect in an object-oriented paradigm.
Assignment =, addition +, subtraction -, comparison ==, etc are all operations. Especially if you consider that you can explicitly define, override, or overload these operations for arbitrary classes (i.e.: data structures) in some languages (e.g. C++), then the primitive int, char, or what have you, are not very different.
Primitive variables don't have operations attached to them. So I feel that unless you have a set of operations defined and attached to it you cannot call it a data structure.
'int' doesn't have any operation attached to it, it can be operated upon with a set of generic operators.
Generic? Then how come 2+2 works, but "ninja" + List<float> doesn't? If the operator was generic, it'd work on anything. It doesn't. It only works on a few predefined types, such as integers.
Ints certainly have a set of operations defined on them. Arithmetic operations such as addition, subtraction, multiplication or division, for example. Most languages also have some kind of ToString()-like functionality defined on integers. But you can't do just anything with an int. For example, you can't pass an int to a function expecting a string. ints have a very specific set of operations defined on them. Those operations just aren't member methods. They come in the form of operators and non-member functions or member methods of other classes. But they are still operations that work on integers.
I don't think, (ref: Wikipedia entry) that Data Structure includes the definition of permissible operations (on operators). Of course, we could cite the C++ class as a counter-example in which we can define overloaded operators. At the same time, we define a structure as just a composite/user defined datatype and do not declare any permissible operations on them. We allow the compiler to figure that out.
'int' doesn't have any operation attached to it, it can be operated upon with a set of generic operators.
Operations are intrinsically linked with the things that they operate on; there's no such thing as generic operations.
This is true in the mathematical sense (< works for in set of integers, but has no meaning for complex numbers), and also in the computer scientific sense (evaluating a + b requires that a and b are or can be converted to compatible types on which the + operation is defined).
Of course, it depends what you mean by "data structure." Others have focused on whether your definition is correct and raise good questions. But what if we say, "Let's ignore the term for now, and focus on what you described?" In other words, what if look at
A piece of data that has a designated interpretation of its value
A set of operations on that data
Then certainly, int qualifies. (If there were no operations on int, we'd all be stuck!)
For a more mathematical approach to programming that begins with these questions, and takes them to what some have called "an algebra of computation," see Elements of Programming by Alex Stepanov and Paul McJones.

What is the purpose of null?

I am in a compilers class and we are tasked with creating our own language, from scratch. Currently our dilemma is whether to include a 'null' type or not. What purpose does null provide? Some of our team is arguing that it is not strictly necessary, while others are pro-null just for the extra flexibility it can provide.
Do you have any thoughts, especially for or against null?
Have you ever created functionality that required null?
Null: The Billion Dollar Mistake. Tony Hoare:
I call it my billion-dollar mistake.
It was the invention of the null
reference in 1965. At that time, I was
designing the first comprehensive type
system for references in an object
oriented language (ALGOL W). My goal
was to ensure that all use of
references should be absolutely safe,
with checking performed automatically
by the compiler. But I couldn't resist
the temptation to put in a null
reference, simply because it was so
easy to implement. This has led to
innumerable errors, vulnerabilities,
and system crashes, which have
probably caused a billion dollars of
pain and damage in the last forty
years. In recent years, a number of
program analysers like PREfix and
PREfast in Microsoft have been used to
check references, and give warnings if
there is a risk they may be non-null.
More recent programming languages like
Spec# have introduced declarations for
non-null references. This is the
solution, which I rejected in 1965.
null is a sentinel value that is not an integer, not a string, not a boolean - not anything really, except something to hold and be a "not there" value. Don't treat it as or expect it to be a 0, or an empty string or an empty list. Those are all valid values and can be geniunely valid values in many circumstances - the idea of a null instead means there is no value there.
Perhaps it's a little bit like a function throwing an exception instead of returning a value. Except instead of manufacturing and returning an ordinary value with a special meaning, it returns a special value that already has a special meaning. If a language expects you to work with null, then you can't really ignore it.
Oh no, I feel the philosophy major coming out of me....
The notion of NULL comes from the notion of the empty set in set theory. Nearly everyone agrees that the empty set is not equal to zero. Mathematicians and philosophers have been battling about the value of set theory for decades.
In programming languages, I think it is very helpful to understand object references that do not refer to anything in memory. Google about set theory and you will see similarities between the formal symbolic systems (notation) that set theorists use and symbols we use in many computer languages.
Regards,
Sam
What's null for you ask?
Well,
Nothing.
I usually think of 'null' in the C/C++ aspect of 'memory address 0'. It's not strictly needed, but if it didn't exist, then people would just use something else (if myNumber == -1, or if myString == "").
All I know is, I can't think of a day I've spent coding that I haven't typed the word "null", so I think that makes it pretty important.
In the .NET world, MS recently added nullable types for int, long, etc that never used to be nullable, so I guess they think its pretty important too.
If I was designing a lanaguage, I would keep it. However I wouldnt avoid using a language that didn't have null either. It would just take a little getting used too.
the concept of null is not strictly necessary in exactly the same sense that the concept of zero is not strictly necessary.
I don't think it's helpful to talk about null outside the context of the whole language design. First point of confusion: is the null type empty, or does it include a single, distinguished value (often called "nil")? A completely empty type is not very useful---although C uses the empty return type void to mark a procedure that is executed only for side effect, many other languages use a singleton type (usually the empty tuple) for this purpose.
I find that a nil value is used most effectively in dynamically typed languages. In Smalltalk it is the value used when you need a value but you don't have any information. In Lua it is used even more effectively: the nil value is the only value that cannot be a key or a value in a Lua table. In Lua, nil is also used as the value of missing parameters or results.
Overall I would say that a nil value can be useful in a dynamically typed setting, but in a statically typed setting, a null type is useful only for talking about functions (or procedures or methods) that are executed for side effect.
At all costs, avoid the NULL pointer used in C and Java. These are artifacts inherent in the implementations of pointers and objects, and in a well designed lanugage they should not be allowed. By all means give your users a way to extend an existing type with a null value, but make them do it explicitly, on purpose---don't force every type to have one by accident. (As an example of explicit use, I recently implemented Bentley and Sedgewick's ternary search trees in Haskell, and I needed to extend the character type with one additional value meaning 'not a character'. For this purpose Haskell provides the Maybe type.)
Finally, if you are writing a compiler, it is good to remember that the easiest parts of the language to compile, and the parts that cause the fewest bugs, are the parts that aren't there :-)
It seems useful to have a way to indicate a reference or pointer that isn't currently pointing at anything, whether you call it null, nil, None, etc. If for no other reason to let people know when they're about to fall off the end of a linked list.
In C NULL was (void*(0)), so it was a type with value(?). But that didn't work with C++ templates so C++ made NULL 0, it dropped the type and became a pure value.
However it was found that having a specific NULL type would be better so they (the C++ committee) decided that NULL will once again become a type (in C++0x).
Also almost every language besides C++ has NULL as a type, or an equivalent unique value not the same as 0 (it might be equal to it or not, but its not the same value).
So now even C++ will use NULL as a type, basically closing the discussions on the matter, since now everyone (almost) will have a NULL type
Edit: Thinking about it Haskell's maybe is another solution to NULL types, but its not as easy to grasp or implement.
A practical example of null is when you ask a yes/no question and don't get a response. You don't want to default to no because it might be important to know that the question wasn't answered in situations where the answer is very important.
Null is not a mistake.
Null means "I don't know yet"
For primitives you don't really need a null (I have to say that strings (in .NET) shouldn't get it IMHO)
But for composite entities it definitely serves a purpose.
You can think of any type as a set along with a collection of operations. There are many cases where it's convenient to have a value with isn't a "normal" value; for example, consider an "EOF" value. for C's getline(). You can handle that in one of several ways: you can have a NULL value outside the set, you can distinguish a particular value as null (in C, ((void *)0) can serve that purpose) or you can have a way of creating a new type, so that for type T, you create a type T' =def { T ∪ NULL }, which is the way Haskell does it (a "Maybe" type).
Which one is better is good for lots of enjoyable argument.
Null is only useful in situations where there are variables with unassigned values. If every variable has a value, then there is no need for null values.
Null is a sentinel value. It's a value that cannot possibly be real data and instead provides meta-data about the variable in use.
Null assigned to a pointer indicates that the pointer is uninitialized. This gives you the ability to detect misuse of uninitialized pointers by detecting dereferences of null valued pointers. If you instead leave the value of a pointer equal to whatever happened to be in memory then you would have crazily irregular program behavior that would be much more difficult to debug.
Also, the null character in a C-style variable length string is used to mark the end of the string.
The use of null in these ways, especially for pointer values, has become so popular that the metaphor has been imported into other systems, even when the "null" sentinel value is implemented entirely differently and has no relation to the number 0.
Null is not the problem - everyone treating, and interpreting null differently is the problem.
I like null. If there was no null, null would only be replaced with some other way for the code to say "I have no clue, dude!" (which some would write "I have no clue, man!", or "I have not a clue, old bean!" etc. and so, we'd have the exact same problems again).
I generalize, I know.
Consider the examples of C and of Java, for example. In C, the convention is that a null pointer is the numeric value zero. Of course, that's really just a convention: nothing about the language treats that value as anything special. In Java, however, null is a distinct concept that you can detect and know that, yes, this is in fact a bad reference and I shouldn't try to open that door to see what's on the other side.
Even so, I hate nulls almost worse than anything else.
CLARIFICATION based on comments: I hate the defacto null pointer value of zero worse than I hate null.
Any time I see an assignment to null, I think, "oh good, someone has just put a landmine in the code. Someday, we're going to be walking down a related execution path and BOOM! NullPointerException!"
What I would prefer is for someone to specify a useful default or NullObject that lets me know that "this parameter has not been set to anything useful." A bald null by itself is just trouble waiting to happen.
That said, it's still better than a raw zero wandering around loose.
That decision depends on the objective of the programing language.
Who are you designing the programing language for? Are you designing it for people who are familiar with c-derived languages? If so, then you should probably add support for null.
In general, I would say that you should avoid violating people's expectations unless it serves a particular purpose.
Take switch-blocks in C# as an example. All case labels in C# must have an explicit control-flow expression in every branch. That is they must all end with either a "break" statement or an explicit goto. That means that while this code is legal:
switch(x)
{
case 1:
case 2:
foo;
break;
}
That this code would not be legal:
switch (x)
{
case 1:
foo();
case 2:
bar();
break;
}
In order to create a "fall through" from case 1 to case 2, it's necessary to insert a goto, like this:
switch (x)
{
case 1:
foo();
goto case 2;
case 2:
bar();
break;
}
This is arguably something that would violate the expectations of C++ programmers who are leaning C#. However, adding that restriction serves a purpose. It eliminates the possibility of an entire class of common C++ bugs. It adds to the learning curve of the language slightly, but the result is a net benefit to the programmer.
If your goal is to design a language targeted at C++ programmers, then removing null would probably violate their expectations. That will cause confusion, and make your language more difficult to learn. The key question is then, "what benefit do they get"? Or, alternatively, "what detriment does this cause".
If you are simply trying to design a "super small language" that can be implemented in the course of a single semester, then the story is different. In that case your objective isn't to be build a useful language targeted at a particular segment of the population. Instead, it's just to learn how to create a compiler. In that scenario, having a smaller language is a big benefit, and so it's worth eliminating null.
So, to recap, I would say that you should:
Identify your goals in creating the language. Who is the language designed for, and what are their needs.
Make the decision based on what helps the target users meet their goals in the best way.
Usually this will make the desired result pretty clear.
Of course, if you don't explicitly articulate your design goals, or you can't agree on what they are, then you are still going to argue. In that case, however, you are pretty much doomed anyways.
One other way to look at null is that it's a performance issue. If you have a complex object containing other complex objects and so on, then it is more efficient to allow for all properties to initially become null instead of creating some kind of empty objects that won't be good for nothing and soon to be replaced.
That's just one perspective that I can't see mentioned before.
What purpose does null provide?
I believe there are two concepts of null at work here.
The first (null the logical indicator) is a conventional program language mechanism that provides runtime indication of a non-initialized memory reference in program logic.
The second (null the value) is a base data value that can be used in logical expressions to detect the logical null indicator (the previous definition) and make logical decisions in program code.
Do you have any thoughts, especially for or against null?
While null has been the bane of many programmers and the source of many application faults over the years, the null concept has validity. If you and your team create a language that uses memory references that can be potentially misused because the reference was not initialized, you will likely need a mechanism to detect that eventuality. It is always an option to create an alternative, but null is a widely known alternative.
Bottom line, it all depends upon the goals of your language:
target programming audience
robustness
performance
etc...
If robustness and program correctness are high on your priority list AND you allow programmatic memory references, you will want to consider null.
BB
If you are creating a statically typed language, I imagine that null could add a good deal of complexity to your compiler.
If you are creating a dynamically typed language, NULL can come in quite handy, as it is just another "type" without any variations.
Null is a placeholder that means that no value (append "of the correct type" for a static-typed language) can be assigned to that variable.
There is cognitive dissonance here. I heard somewhere else that humans cannot comprehend negation, because they must suppose a value and then imagine its unfitness.
My suggestion to your team is: come up with some examples programs that need to be written in your language, and see how they would look if you left out null, versus if you included it.
Use a null object pattern!
If you language is object oriented, let it have an UndefinedValue class of which only one singleton instance exists. Then use this instance wherever null is used. This has the advantage that your null will respond to messages such as #toString and #equals. You will never run into a null pointer exception as in Java. (Of course, this requires that your language is dynamically typed).
Null provides an easy way out for programmers who haven't completely thought through the logic and domains needed by their program, or the future maintenance implications of using a value with essentially no clear and agreed upon definition.
It may seem obvious at first that it must mean "no value", but what that ACTUALLY means depends on context. If, for instance LastName === null, does that mean that person doesn't have a last name, or that we don't know what their last name is, or that it hasn't be entered into the system yet? Does null equal itself, or doesn't it? In SQL it does not. In many languages it does. But if we don't know the value of personA.lastName, or personB.lastName, how can we know that personA.lastName === personB.lastName, eh? Should the result be false, or .. . null?
It depends on what you're doing, which is why it's dangerous and silly to have some kind of system wide value that can be used for any kind of situation that kind of looks like "nothing", since how other parts of your program and external libraries or modules can't really be depended upon to correctly interpret what you meant by "null".
You're much better off clearly defining the DOMAIN of possible values of lastName, and exactly what every possible value actually means, rather than depending on some vague systemwide notion of null, which may or may not have any relevance to what you're doing, depending on which language you're using, and what you're trying to do. A value, which may in fact, behave in exactly the wrong way when you begin to operate on your data.
Null is to objects what 0 is to numbers.