TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Swift: Madness of Generic Integer

148 pointsby krzyzanowskimabout 10 years ago

14 comments

gilgoomeshabout 10 years ago
To summarize, the author has two problems:<p>1. Bit shift is not part of the IntegerType protocol, when it should be (although the author could avoid the issue by accumulating the bytes in a UIntMax instead of the generic type).<p>2. Construction from (and conversion to) a UIntMax bit pattern is not part of the IntegerType protocol, when it should be (done correctly, this addresses the author&#x27;s sign <i>and</i> construction complaints)<p>The author incorrectly claims&#x2F;implies that these are problems with generics or protocols or the diversity of integer types in Swift. They&#x27;re really a problem of omissions in the standard library protocols that are forcing some very cumbersome workarounds. The necessary functionality exists, it just isn&#x27;t part of the relevant protocols. Submit these as bugs to Apple.<p>Edit:<p>As a follow up, here&#x27;s a version that gets around the standard library limitations using an unsafe pointer...<p><pre><code> func integerWithBytes&lt;T: IntegerType&gt;(bytes:[UInt8]) -&gt; T? { if (bytes.count &lt; sizeof(T)) { return nil } var i:UIntMax = 0 for (var j = 0; j &lt; sizeof(T); j++) { i = i | (UIntMax(bytes[j]) &lt;&lt; UIntMax(j * 8)) } return withUnsafePointer(&amp;i) { ip -&gt; T in return UnsafePointer&lt;T&gt;(ip).memory } } </code></pre> Of course, at that point, why not simply reinterpret the array buffer directly...<p><pre><code> func integerWithBytes&lt;T: IntegerType&gt;(bytes:[UInt8]) -&gt; T? { if (bytes.count &lt; sizeof(T)) { return nil } return bytes.withUnsafeBufferPointer() { bp -&gt; T in return UnsafePointer&lt;T&gt;(bp.baseAddress).memory } }</code></pre>
评论 #9142396 未加载
评论 #9143179 未加载
评论 #9143643 未加载
评论 #9142322 未加载
评论 #9143296 未加载
ChuckMcMabout 10 years ago
Wow that takes me back. Back to a conference room where we were talking about Integers in Java. If you made it a class, an Integer could carry along all this other stuff about how big it was, what the operators were, etc. But generating code for it was painful because your code had to do all of these checks when 99% of the time you probably just wanted the native integer implementation of the CPU. And Boolean&#x27;s were they their own type or just a 1 bit Integer? And did that make an enum {foo, bar, baz, bletch, blech, barf, bingo} just a 3 bit integer?<p>Integers as types can compile quickly, but then you need multiple types to handle the multiple cases. Essentially you have pre-decoded the size by making into a type.<p>At one point you had class Number, subclasses Real, Cardinal, and Complex, and within those a constructor which defined their precision. But I think everyone agreed it wasn&#x27;t going to replace Fortran.<p>The scripting languages get pretty close to making this a non-visible thing, at the cost of some execution speed. Swift took it to an extreme, which I understand, but I probably wouldn&#x27;t have gone there myself. The old char, short, long types seem so quaint now.
评论 #9141857 未加载
评论 #9143014 未加载
评论 #9142365 未加载
Animatsabout 10 years ago
I once, many years ago, wrote something titled &quot;Type Integer Considered Harmful&quot;. (This was way back during the 16-32 bit transition). My position was that the user should declare integer types with ranges (as in Pascal and Ada), and it was the compiler&#x27;s job to insure that intermediate variables must not overflow unless the user-defined ranges would also be violated. Overflowing a user range would be an error. The goal was to get the same answer on all platforms regardless of the underlying architecture.<p>The main implication is that expressions with more than one operator tend to need larger intermediate temporary variables. (For the following examples, assume all the variables are the same integer type.) For &quot;a = b * c&quot;, the expression &quot;b * c&quot; is limited by the size of &quot;a&quot;, so you don&#x27;t need a larger intermediate. But &quot;a = (b * c)&#x2F;d&quot; requires an temporary big enough to handle &quot;b * c&quot;, which may be bigger than &quot;a&quot;. Compilers could impose some limit on how big an intermediate they supported.<p>This hides the underlying machine architecture and makes arithmetic behave consistently. Either you get the right answer numerically, or you get an overflow exception.<p>Because integer ranges weren&#x27;t in C&#x2F;C++, this approach didn&#x27;t get much traction. Dealing with word size differences became less of an issue when the 24-bit, 36-bit, 48-bit and 60-bit machines died off in favor of the 32&#x2F;64 bit standard. So this never became necessary. It&#x27;s still a good way to think about integer arithmetic.
评论 #9142837 未加载
评论 #9142947 未加载
评论 #9142918 未加载
Filligreeabout 10 years ago
For amusement value, the Haskell equivalent is:<p><pre><code> import Data.Bits import Data.List(unfoldr) f :: (Num a, Bits a) =&gt; a -&gt; [a] f = unfoldr $ \case 0 -&gt; Nothing n -&gt; Just (n .&amp;. 0xff, n `shift` 8)</code></pre>
评论 #9141428 未加载
shurcooLabout 10 years ago
Generic code is like nerd sniping.<p>I look at this and think &quot;why would you want to write generic code for all those ints?&quot;<p>The integer types may look similar but they&#x27;re different in more ways than they&#x27;re similar. They have different bit sizes, different signedness. The CPU literally has to do different things depending if its `uint8` or `int64`. So why do you want or expect one piece of code that does it all?<p>It&#x27;s just so much easier and faster to do it like Go, have non-generic functions that do exactly what you want and as a result, get meaningful work done. It&#x27;s faster to write (because you don&#x27;t need to figure out how to do in a generic way), faster and easier to read, and possible to make changes to one func but not others.
评论 #9141466 未加载
评论 #9141558 未加载
评论 #9141643 未加载
评论 #9141491 未加载
评论 #9142008 未加载
评论 #9141624 未加载
lectrickabout 10 years ago
I guess this sort of gets at the crux of the issue: Do you want it to be more like a scripting language (which would basically give you the mathematical equivalent of &quot;integer&quot; including unlimited size) at the cost of speed, or do you want it to be closer to the implementation in the CPU, which entails dealing with 8&#x2F;16&#x2F;32&#x2F;64 bit limits and sign bits?<p>Why not have a way to do both? You can get an easy-to-use Int when speed is less of a concern, and can deal with Int16&#x27;s, Int32&#x27;s, UInt32&#x27;s and whatnot when the job demands it.
评论 #9144113 未加载
chvidabout 10 years ago
I think you all are being too nice to Apple.<p>I had a similar experience as the blog post author. I spent many hours battling generics and the huge forest of (undocumented) protocols to do something seemingly trivial. I just gave up rather than try to pin down exactly what was wrong in a long and detailed blog post.<p>The prevailing answer to everything seem to be: Write a bug report to Apple and use Objective-C (or Swift&#x27;s UnsafePointer and related).<p>This ignores what I think really is the issue here: Swift has an overly complex type system. This picture:<p><a href="http://swiftdoc.org/type/Int/hierarchy/" rel="nofollow">http:&#x2F;&#x2F;swiftdoc.org&#x2F;type&#x2F;Int&#x2F;hierarchy&#x2F;</a><p>Tells a lot. And this is from unofficial documentation that has been generated from Swift libraries. When you read the documentation Apple provides there is little explanation of this huge protocol hierarchy and the rationale behind it.<p>It seems to me that: Swift has been released in a rush with bugs even in the core language and compiler. Lacking documentation. And of course even a larger number of bugs in the IDE support, debugging etc.<p>Secondly: Swift battles the problem of easy-to-understand typesafe generics like so many other languages only it has it much worse: It carries a lot of stuff from Objective-C and it has to support easy interoperability. Plus it has ideas like not allowing implicit conversion of number types (requiring an integer added to a double to be explicitly converted to a double) causing the big type system to show it&#x27;s messy head again and again.<p>I really want to love Swift but it will take years for Swift to be as clean and productive as Objective-C.<p>I my opinion what Apple should have done was to create the &quot;CoffeeScript&quot; of Objective-C. A language that essentially was Objective-C in terms of language features but with a concise syntax.
grimlckabout 10 years ago
How does [0xFF, 0xFF, 0xFF, 0xFF], interpreted as a UInt32 turn into 16777215?<p>I would have guessed 4294967295
评论 #9141524 未加载
评论 #9141525 未加载
评论 #9142732 未加载
thought_alarmabout 10 years ago
The Swift equivalent of his first `NSData` example is essentially this:<p><pre><code> func integerWithBytes&lt;T:IntegerType&gt;(bytes:[UInt8]) -&gt; T { let valueFromArrayPointer = { (arrayPointer: UnsafePointer&lt;UInt8&gt;) in return unsafeBitCast(arrayPointer, UnsafePointer&lt;T&gt;.self).memory } return valueFromArrayPointer(bytes) } let bytes:[UInt8] = [0x00, 0x01, 0x00, 0x00] let result: UInt32 = integerWithBytes(bytes) assert(result == 256)</code></pre>
frozenportabout 10 years ago
&quot;All problems in computer science can be solved by another level of indirection, except of course for the problem of too many indirections.&quot; ~David John Wheeler
bluehexabout 10 years ago
I wouldn&#x27;t expect a much better design from a language developed behind closed doors with no community input.<p>Now all we can do is file bugs against Apple, and hope they improve it; they who chose to release a new language with but three months of public beta. They obviously didn&#x27;t care much to have their designs tested or incorporate feedback then.
cjensenabout 10 years ago
&gt; More or less, what I want to archive can be done with old world NSData: data.getBytes(&amp;i, length: sizeofValue(i))<p>That doesn&#x27;t work in C&#x2F;C++ if you are using a modern optimizer.<p>C does not have the other Swift issues the author mentions, so shifting into the largest int and casting from there does work.
rismayabout 10 years ago
I&#x27;m glad I&#x27;m not the only one having this issue.
IgorPartolaabout 10 years ago
So no macros? Seriously, isn&#x27;t that the way to solve this?
评论 #9143542 未加载