Show Lecture.DuckTyping as a slide show.
CS253 Duck Typing
🦆 🦆 🦆 The Saying 🦆 🦆 🦆
“If it walks like a duck,
and quacks like a duck,
then it’s a duck.”
This saying stresses common sense over formal definition. If I were
doing 200mph on I-25 in Luke Skywalker’s speeder, I wouldn’t get far
telling a state trooper that it’s “not a car”. The law would probably
view it as a car, even without wheels.
Rules for Rulers
- The rules for president of the USA are:
- natural born citizen
- thirty-five years old
- resident for fourteen years
- winner of the Electoral College
- The rules for king or queen of the UK are:
- USA: what you can do (well, in theory)
- UK: who you are
Rules for Containers
- The rules for storing something in an STL container are:
- default ctor
- copy-ctor
- assignment operator
- less-than comparable, for ordered containers
Enforcement
- Who enforces the rules for ruling the USA or UK?
- Who enforces the rules for STL containers?
Example
A vector requires that its stored type be copyable, both via copy ctor and
assignment operator.
You can have a vector<string>
, because strings are copyable:
string now = "2024-11-22T01:10:13"; // ISO 8601, baby!
vector<string> v;
v.push_back(now);
cout << v.front() << '\n';
2024-11-22T01:10:13
Example
How about a non-copyable class?
vector<istream> v;
cout << "size=" << v.size();
size=0
That worked fine! Well, we might try adding something
to the vector …
vector<istream> v;
v.push_back(cin);
In file included from /usr/include/c++/8/x86_64-redhat-linux/bits/c++allocator.h:33,
from /usr/include/c++/8/bits/allocator.h:46,
from /usr/include/c++/8/string:41,
from c.cc:1:
/usr/include/c++/8/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::basic_istream<char>; _Args = {const std::basic_istream<char, std::char_traits<char> >&}; _Tp = std::basic_istream<char>]':
/usr/include/c++/8/bits/alloc_traits.h:475: required from 'static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::basic_istream<char>; _Args = {const std::basic_istream<char, std::char_traits<char> >&}; _Tp = std::basic_istream<char>; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::basic_istream<char> >]'
/usr/include/c++/8/bits/stl_vector.h:1079: required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::basic_istream<char>; _Alloc = std::allocator<std::basic_istream<char> >; std::vector<_Tp, _Alloc>::value_type = std::basic_istream<char>]'
c.cc:2: required from here
/usr/include/c++/8/ext/new_allocator.h:136: error: use of deleted function
'std::basic_istream<_CharT, _Traits>::basic_istream(const
std::basic_istream<_CharT, _Traits>&) [with _CharT = char; _Traits =
std::char_traits<char>]'
How enforcement “works”
- STL containers do not contain explict checks for
default-constructability, copy construction, and assignability.
- Difficult, if not impossible.
- The STL containers merely use these operations.
- If they work, great!
- If they fail, well, enjoy your C++ error messages!