duangsuse::Echo
718 subscribers
4.26K photos
130 videos
583 files
6.48K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
duangsuse::Echo
慢慢来吧,先写 RangeMap 算…… 🤔
辣鸡 Java 的 default in interfaces (mixin) 真是辣鸡,辣眼睛。
我 TM 都看不清哪些是我该 override 的了
辣鸡 Java 的 stdlib 实在是太愚蠢了,尽写一些无关紧要的接口定义,本来可以划分的它偏放在一起
而且,居然是 unchecked!真不知道是不是没提供新的,基于 Parametrized types 的版本
duangsuse::Echo
而且,居然是 unchecked!真不知道是不是没提供新的,基于 Parametrized types 的版本
因为 Java 没有真实泛型,都是基于泛型擦除的 compile-time only 实现,害得我都不得不 unchecked cast 了,气死我了
比方说它非得弄个 get(Object) 的 API,虽然擦除后 get(K), get(Object) 都是 get(Object),我 TM…… 还得被,而且,我拿不到 reified 的类 Class<T>,不可能自然也不应该运行时检查类型

Java 辣鸡!!!
而且还不得不写一堆无聊的 default,我不知道 Java 7 里会怎么样
不愧是 Java,写起来真的很难受,而且我还总是怀疑,型变性会不会出问题。
我们怎么能这样批评 Java 呢,Java 君活得那么努力,努力到写了 90% 都是 boilerplate,我还以为我在做什么不得了的事情,以至于花了很长时间。
其实都是 🌬!emmmm
我还以为我 100+ 行写了什么不得了的东西,其实他们要测试,你知道为什么要测试吗?因为一大堆全都是无聊的代码!
为什么一些无聊的东西还需要测试?因为人的精力是有限的,无聊的东西看多了,有用的东西就容易写错!!!
但是不管写多长都 1.2K 的体积很令我满意,当然我知道,缩减体积不是程序员该做的事情,可是我就是讨厌 Kotlin 过了一遍 Proguard 还是 50K+ 的类文件大小……
反正 Java 还可以翻译到 Kotlin 的
IDEA 又把我的分析能力比了下去,我想破脑袋也想不到 (null == null).
为什么我感觉像是在吃 💩
同样的代码,Haskell 里就是

{-# LANGUAGE GADTs #-}
data Ray t a = (Ord t) => Shadow t a | (Ord t) => White t


Kotlin 里也不困难

sealed class Ray<out T: Comparable<T>, out V> {
data class White<T>(val c: T): Ray<T, *>
data class Shadow<T, V>(val c: T, val x: V): Ray<T, V>
}


可是 Java 里要写十几行,我 (TMD) 快写疯了!
写了半天这类无聊的东西,那个至关重要的二分查找我都快忘记了 💭
而且因为他们很多,还得写不少测试

我终于明白为什么 Java 都是『大项目』了
This media is not supported in your browser
VIEW IN TELEGRAM
MD 个 🍻,气死我了,看来没时间不敢用 Java
说起来,没 Kotlin Multiplatform,JS/JVM 还得分着写(虽然有别的翻译器)
那更浪费时间

还是 TypeScript 好
可我不喜欢动态类型
Kotlin 的类文件体积不好缩减

不管动态不动态,JDK Collections Framework 这种把一大堆什么 putAll, isEmpty, entrySet(), values(), containsKey() 不给 default 的,简直是魔鬼!
难道我的 KvMap 要扩展它的接口?难道我的 KvMap 不该在 pass 掉一些辣鸡操作的前提下扩展支持 Map 的接口???

吃完饭我会讲一下 RangeMap 的理论
尼玛,我以为我效率多高呢。
range_map.zip
25.5 KB
我不玩了,要玩你们看去吧,我进入第一次重写来的 #java #code #share
@data @override @pure @fun @overrideFun
@in @out @some
@get @set @protectedGet @protectedSet

等我先把这些 kt4java Annotation 实现再说
duangsuse::Echo
@data @override @pure @fun @overrideFun @in @out @some @get @set @protectedGet @protectedSet 等我先把这些 kt4java Annotation 实现再说
├── [ 1.8K]  Data.class
├── [ 1.1K] KvMap$1.class
├── [ 917] KvMap$KvPair$Mutable$Of.class
├── [ 505] KvMap$KvPair$Mutable.class
├── [ 2.0K] KvMap$KvPair$Of.class
├── [ 667] KvMap$KvPair.class
├── [ 2.5K] KvMap$Mutable.class
├── [ 4.5K] KvMap.class
├── [ 447] OperationNotSupportedException$Mutability.class
├── [ 1.1K] OperationNotSupportedException.class
├── [ 1.6K] RangeIE$IntRange.class
├── [ 1.6K] RangeIE$LongRange.class
├── [ 381] RangeIE.class
├── [ 1.7K] RangeMap$Mutable.class
├── [ 990] RangeMap$Ray$Shadow.class
├── [ 1.1K] RangeMap$Ray$White.class
├── [ 1.1K] RangeMap$Ray.class
├── [ 1.7K] RangeMap.class
└── [ 258] RayRangeMap.class

其实为什么不用 Kotlin,还要加上 annotation processing 也用 Java,这张看得很明白
Kotlin 必须有 Kotlin Runtime,那可大啊,而且小不了…… Scala 也一样
他们的通病……

有时候,我觉得如果利用 Annotation 扩展,Java 也不一定会怎么样差……

你们看了我上面的消息,肯定认为我恨死 Java 了,其实我真的不是恨 Java,我『恨』的是辣鸡编程风格。
我是函数式风格的程序员,看不惯一大堆 boilerplate 代码(何况我要对正在编写的东西实时进行模拟的,太多行代码会严重影响我的手感,太复杂的继承结构和数据封装、无必要的抽象更是会导致我像吃了 💩 一样难受)。

很多人不知道怎么写 Annotation Processor(不过知道怎么用),但是绝大部分人都会写 C Macro,我相信很多 Rust 的程序员也都会写和 regex 语法很像的 macro_rules!
对于我来说,代码生成、修改 AST 就是我的老本行…… 混饭吃的东西,当然这个不是不可说(其实我也是从周老的《JVM 最佳实践》抄的)

怎么说呢,我先举一段 #Kotlin 代码,如果连这个都搞不懂就不要看了(当然也看不懂,因为你连括扑「排序」都不会,还需要学习啊),用我写出来的库吧。

sealed class SumTree {
data class Group(val children: Iterable<SumTree>): SumTree()
data class Tip(val n: Int): SumTree()
interface Visitor<out R> {
fun see(x: Tip):R fun see(g: Group):R }
fun <R> rewriteBy(vis: Visitor<R>): R = when (this) {
is Tip -> vis.see(this)
is Group -> vis.see(this)
}
}

object Sumer : SumTree.Visitor<Int> {
override fun see(x: SumTree.Tip) = x.n
override fun see(g: SumTree.Group) = g.children.sumBy { sum(it) }
private fun sum(t: SumTree) = t.rewriteBy(this)
}

>>> SumTree.Group(listOf(1,2,3).map(SumTree::Tip).asIterable())
Group(children=[Tip(n=1), Tip(n=2), Tip(n=3)])
>>> SumTree.Group(listOf(1,2,3).map(SumTree::Tip).asIterable()).rewriteBy(Sumer)
6

(之前我一直以为我有 see: Sumer.(Tip) -> R; Sumer.(Group) -> R 就万事大吉了,艹,还得 Visit fun 专门去 instance check
(其实我也可以抽象出一个 Tip.plus(Tip): T,这样就能直接在一个群(group),而不是 List<Int> 什么的里执行计算

也就是 Javac 的 Inline annotation processor JSR-269 API 啦,javax.annotation.processing.AbstractProcessor
你要处理生成的,就是 javax.lang.model.element, Java 的 AST,可惜是不可改变的

一段代码,我举个简单的例子,比如说给方法的名字加前缀:

(其实已经不简单了…… 比较长,而且实现的东西不多……
看来自动生成代码还是要更多努力才行的,不过我不是说 Javac 这样就理所应当。

骚一点的(类似 Python decorator 的手段,我把部分数据加在特定的 @interface 上,而不是 Annotation Processor 看的那种上面)
simple-ap.zip
11.6 KB
🐴 的,Annotation Processor 那么花,居然只能用来「访问」部分数据,它不能改变源语法树!
@NamePrefixed(prefix = "Aa") public class A {}
[DuangSUSE@duangsuse]~/Projects/essay/simple-ap/out/production/kt4java% javac -cp . -processor Processor ../../../src/A.java -XprintRounds -XprintProcessorInfo
循环 1:
输入文件: {A}
注释: [NamePrefixed]
最后一个循环: false
处理程序Processor与[NamePrefixed]匹配并返回true。
注: Prefix: Aa from [NamePrefixed]
警告: Name A does not started with Aa
循环 2:
输入文件: {}
注释: []
最后一个循环: true
1 个警告


请问,衬衫的价格是多少?这 TMD 有个 🐔 用???(忽视英文语法错误)
原来它只能用来『访问』AST!而且还是『部分地』访问!
不排除,我的 Parser.kt 写出来以后会对 AST 模式匹配有很大帮助
有再大帮助也没有暖用