Forwarded from dnaugsuz
Jawa 也有一些可以“跨运行时平台”的实现,比如 JSweet transpiler
JVM 本身对 C, C++ 等所谓 Native 语言的编译器也有实现的,至少人家还支持 JNI 扩展底层访问性呢 [比如说这个]
曾经的 GCJ (GNU Compiler for Java) 也是支持 Java -> native code 的
现在 GraalVM 、之前 ExcelsiorJET 不也在吹 AOT 编译的说
JVM 本身对 C, C++ 等所谓 Native 语言的编译器也有实现的,至少人家还支持 JNI 扩展底层访问性呢 [比如说这个]
曾经的 GCJ (GNU Compiler for Java) 也是支持 Java -> native code 的
现在 GraalVM 、之前 ExcelsiorJET 不也在吹 AOT 编译的说
JSweet
JSweet: a transpiler to write JavaScript programs in Java
JSweet is an open transpiler from Java to TypeScript/JavaScript with more than 1000 well-typed JavaScript libraries.
Forwarded from Yuuta
不懂那么深奥的,反正 J AV A 给我的感觉就是有大又笨又老(x
Forwarded from dnaugsuz
Java 是很老,但也是 Kotlin 它干爹啊 🌝
Forwarded from Yuuta
不能完全算吧?从某种意义上说 Kotlin 是 “兼容” Java(x
Forwarded from dnaugsuz
C 自己也有不好的地方,比如 Null safety
你得自己写代码处理输入 ptr 可能为空但不应该为空的情况,而 Kotlin 是自动处理
如果你是比较优秀的程序员,肯定会用子程序对 raw FFI 进行高层封装(比如,一个
这一点 ice1000 的博文《形式验证、依赖类型与动态类型》讲得很好
你得自己写代码处理输入 ptr 可能为空但不应该为空的情况,而 Kotlin 是自动处理
如果你是比较优秀的程序员,肯定会用子程序对 raw FFI 进行高层封装(比如,一个
Optional<T> 会被你弄成 @Throws(XXXNotFound::class) 的形式),这样就避免了每次检查 null safety 的问题,Kotlin 只是做了对的事情,检查了 null 指针的可能性,把运行期的错误提升到了编译期,虽然 Kotlin 它不 Check Exceptions... 也有自己的道理,但完全不 sound (没 error 也没 warn)的编译检查还是....这一点 ice1000 的博文《形式验证、依赖类型与动态类型》讲得很好
Forwarded from dnaugsuz
是啊,几乎是能完全兼容 Java,至少排除元编程的情况下是完全双向兼容
但是 Java 依然还是可以用的,这点不可否认,不过我要说的是,即使是被所有人批判的 Java,也不是被人完全理解的,Java 自己看起来很简单,就算排除掉 JVM,某些细节很多资深工程师也都是说不上来,比方说所有类型表达式的求值顺序、所有语法结构、Annotation Processor 加入后的编译流程
毕竟『精通』和『创造』还是有区别的,一个是使用,一个是实现,实现意味着你得什么都知道,使用是你用什么学什么。
当然如果工程师实现过符合标准的 Java 编译器算我没说
但是 Java 依然还是可以用的,这点不可否认,不过我要说的是,即使是被所有人批判的 Java,也不是被人完全理解的,Java 自己看起来很简单,就算排除掉 JVM,某些细节很多资深工程师也都是说不上来,比方说所有类型表达式的求值顺序、所有语法结构、Annotation Processor 加入后的编译流程
毕竟『精通』和『创造』还是有区别的,一个是使用,一个是实现,实现意味着你得什么都知道,使用是你用什么学什么。
当然如果工程师实现过符合标准的 Java 编译器算我没说
Forwarded from dnaugsuz
🤔 说起来我这么开放地发了那么多字含代码的内容,会不会本群不欢迎贴代码呢?
这么久也没被踢,感觉很不对劲(跑
这么久也没被踢,感觉很不对劲(跑
dnaugsuz
🤔 说起来我这么开放地发了那么多字含代码的内容,会不会本群不欢迎贴代码呢? 这么久也没被踢,感觉很不对劲(跑
This media is not supported in your browser
VIEW IN TELEGRAM
duangsuse::Echo
== 无关的 Win32 Form API static Application.EnableVisualStyles(); static Application.SetCompatibleTextRenderingDefault(bool); static Application.Run(Form); — namespace System.Windows.Forms { Form } class Form { protected void OnLoad(EventArgs); } == 有关的…
#Statement 可能有一些人觉得我只看理论,只会空谈不能实践,一样是废物一个,但是我相信这只是时间不足的问题而已,现在我已经开始准备学着实践了,上面嵌入的代码就是证明。
可能也会被人喷废话太多,或者『这些东西太简单,你去学学写 Android 设计模式、你去学学 JavaEE 设计模式』什么的
但我相信,只要理论做足了、代码写多了,那些看起来很魔法的东西也是可以做到的。
反而是某些地方使用的某些设计模式,是真正意义上的凭空增加复杂度,只是因为面向对象只允许受限制的函数指针,(Java 里)我们要起无数个方法名,在所有地方都要用匿名内部类(曾经没有 Lambda 的时候),只是为了实现某一个类似
一些诸如依赖注入的耦合问题,不少函数式编程语言里都有类似的解决方案,它们看起来会更优雅,但函数式给你最大的礼物其实不是好看的代码,而是对程序逻辑本身拥有更好的直觉,让你用最直白最通透的视角看一切程序,最大程度上泛化编程,让你不止不再局限与某种语言,甚至不再害怕新的编程范式,实际上这才是优秀的工程师会需要的东西。
我觉得理论重于普通的工程,因为理论可以引导我走到更高的地方或者更低的地方,高到范畴论\逻辑和一些数学、低能看到电子元件、信号、处理器的晶震、逻辑门、一个一个二进制位、时序电路、触发器,让我完全理解某些模式、算法、模型,给我一种直觉,而不是学一个懂一个、抄代码看文档改代码,我要把所有代码默写下来,我觉得这才是我追求的东西,我追求的是技术,但仅仅是技术而已,而不是它伴生或者为之而生的其他东西。
"Talk is cheap, show me the code." Linux Kernel 的创造者,Linus 说过这句话
可是有时候,恰恰 talk,恰恰是设计某件东西才是最困难的,在没有一个设计大纲,算法没有弄出门路、模型完全还没有彻底熟悉之前想 "write code" 是不对的,它只会让你写出糟糕的代码,而且如果要实现的东西本身没有那么简单即得,你花在调试上的时间绝对会比理论准备可能花的时间多。
软件工程有个名词,叫做『代码复用』,已经实现了一遍的逻辑就不要再来写第二次了,它对程序代码的可维护性、可移植性、可读性都有很大的好处。
实际上做好理论,就是做好了最好的“代码复用”。
有些人可能知道一种叫做“文学化编程”的东西,它把编程和对自己程序最直白的解释结合在了一起,难道这不是理论和实践最完美的结合吗?
但在某些领域,无法用简单而复杂难看的堆砌替换优雅但是难做的设计的领域,Literate Programming 是最合适的编程方法
它的确强调了程序员必须有好的思路才能做到 Literate Programming,也提高了编程的门槛(因为它要求你理解很多本来抄代码就 OK 的东西),但这不正是优秀的程序设计者所必须做到的事情吗?
🤔
这是结构化编程的宣言,当然其他范式还有别的看法,但有一点是一致的:
不抄代码无以至今日,不学算法无以终余年。
可能也会被人喷废话太多,或者『这些东西太简单,你去学学写 Android 设计模式、你去学学 JavaEE 设计模式』什么的
但我相信,只要理论做足了、代码写多了,那些看起来很魔法的东西也是可以做到的。
反而是某些地方使用的某些设计模式,是真正意义上的凭空增加复杂度,只是因为面向对象只允许受限制的函数指针,(Java 里)我们要起无数个方法名,在所有地方都要用匿名内部类(曾经没有 Lambda 的时候),只是为了实现某一个类似
FunctionalInterface 的东西... 现在也还是要记类名,因为没有 Java 10 里才出现的 var!一些诸如依赖注入的耦合问题,不少函数式编程语言里都有类似的解决方案,它们看起来会更优雅,但函数式给你最大的礼物其实不是好看的代码,而是对程序逻辑本身拥有更好的直觉,让你用最直白最通透的视角看一切程序,最大程度上泛化编程,让你不止不再局限与某种语言,甚至不再害怕新的编程范式,实际上这才是优秀的工程师会需要的东西。
我觉得理论重于普通的工程,因为理论可以引导我走到更高的地方或者更低的地方,高到范畴论\逻辑和一些数学、低能看到电子元件、信号、处理器的晶震、逻辑门、一个一个二进制位、时序电路、触发器,让我完全理解某些模式、算法、模型,给我一种直觉,而不是学一个懂一个、抄代码看文档改代码,我要把所有代码默写下来,我觉得这才是我追求的东西,我追求的是技术,但仅仅是技术而已,而不是它伴生或者为之而生的其他东西。
"Talk is cheap, show me the code." Linux Kernel 的创造者,Linus 说过这句话
可是有时候,恰恰 talk,恰恰是设计某件东西才是最困难的,在没有一个设计大纲,算法没有弄出门路、模型完全还没有彻底熟悉之前想 "write code" 是不对的,它只会让你写出糟糕的代码,而且如果要实现的东西本身没有那么简单即得,你花在调试上的时间绝对会比理论准备可能花的时间多。
软件工程有个名词,叫做『代码复用』,已经实现了一遍的逻辑就不要再来写第二次了,它对程序代码的可维护性、可移植性、可读性都有很大的好处。
实际上做好理论,就是做好了最好的“代码复用”。
有些人可能知道一种叫做“文学化编程”的东西,它把编程和对自己程序最直白的解释结合在了一起,难道这不是理论和实践最完美的结合吗?
根据高德纳本人所说,文学编程为高质量程序而生,因为它强迫程序员显式描述程序背后的思路,让不充分的设计决策无所遁形。高德纳先生是谁?他是美国的计算机科学家 Donald Ervin Knuth
高德纳还声称文学编程提供了一流的文档系统,它并非插件,而是随着编程思路的慢慢展现而不断自然发展的过程。
著名计算机科学家,斯坦福大学计算机系荣誉退休教授。高德纳教授为现代计算机科学的先驱人物,创造了算法分析的领域,在数个理论计算机科学的分支做出基石一般的贡献。在计算机科学及数学领域发表了多部具广泛影响的论文和著作。1974年图灵奖得主。
高德纳所写的《计算机程序设计艺术》是计算机科学界最受高度敬重的参考书籍之一。他也是排版软件TeX和字体设计系统Metafont的发明人。
实际上使用 Literate Programming,虽然可能“有违简洁”“开发效率低下”(而且在某些逻辑非常简单的程序里,的确相当耗时间) [code example]但在某些领域,无法用简单而复杂难看的堆砌替换优雅但是难做的设计的领域,Literate Programming 是最合适的编程方法
它的确强调了程序员必须有好的思路才能做到 Literate Programming,也提高了编程的门槛(因为它要求你理解很多本来抄代码就 OK 的东西),但这不正是优秀的程序设计者所必须做到的事情吗?
🤔
程序 = 数据结构 + 算法 — Niklaus Wirth这是结构化编程的宣言,当然其他范式还有别的看法,但有一点是一致的:
算法是程序的灵魂
既然编程就是在利用语言的抽象,描述你的算法逻辑,为什么不把它明明白白地写出来呢? 🌝不抄代码无以至今日,不学算法无以终余年。
Wikipedia
文学编程
文学式编程(英語:literate programming)是由高德纳提出的编程方法,希望能用來取代结构化编程范型。
Forwarded from Richard Yu
因为不是C/C++,谁知道有没有指针?没的话那就传个0吧。C++我会写nullptr。
Forwarded from dnaugsuz
如果没有指针类型的话也是可能的,但是,如果是我也会搞个全局的常量
如果类型系统菜,程序员负责给它洗地
nullptr, 尽可能避免混淆如果类型系统菜,程序员负责给它洗地
Forwarded from Richard Yu
"" 不代表 nullptr,它是有一个地址的。
Forwarded from dnaugsuz
是啊,所以我说是一个常量
const char *EMPTY_CHARP = "";
这里我没有指定具体分配位置,但它是常量,换句话说编译器喜欢内联也可以直接翻译成GetModuleHandle("");
或者const static char EMPTY_CHARP[] = {'\0'};
然后 GetModuleHandle(EMPTY_CHARP);
duangsuse::Echo
我觉得就 Scanner 的逻辑结构上应该不够优雅,state 几乎是个笑话、lineDoUntil 非得加一个『keepLastLineOnce』才能用(doUntil 是在 scan body 里看到 new message header 的时候用的,可是等到这个 Message 返回,新 message 头会被下一次 iteration 直接忽视掉(因为我没设计好数据流,然后每次由判断 hasNext 的函数读新行的),导致漏掉偶数消息,不得不引入类似『mark/reset』的机制才可以),不过能用就好(跑路…
后来我会发现这个『keepLastLineOnce』其实就是一个长度为 1 的 reset buffer,不过因为比较短,就没有使用数组存放
—
所谓的 keepLastLineOnce 功能,就是
[Hello world]
实际上是告诉 stream 下次我
lookAhead1:
其实本质上和这么做是没有不同之处的
若 reset buffer 还为空,则读入一行返回,此时即使长度为 1 的 buffer 充盈
则返回上一个字符,把 boolean (这里可以视为一位二进制数值 i1)
否则就向前进一位,并且把已读数据加入 buffer
以后我要再写类似的解析程序,就会直接使用 mark/reset 了
—
所谓的 keepLastLineOnce 功能,就是
String hello = readLine(); // "Hello"但是如果这么写
String world = readLine(); // "world"
readLine(); // EOFException
[Hello world]
String hello = readLine(); // lastLine=null, result="Hello"就可以实现 lookAhead1 的功能:我可以向后阅读一个项目之后若无其事地告诉 stream 向前 <- 移动一个字符,
String world = readLine(); // lastLine="Hello", result="world"
keepLastLineOnce = true;
readLine(); // Hello
实际上是告诉 stream 下次我
nextLine() 的时候给我之前存下已读的输入 @-1,但实际上我已经读过了下一个字符),然后决定我做什么分支(状态迁移)lookAhead1:
var ln = readLine();// next 1 char
keepLastLineOnce = true;// reset buffer @-1
其实本质上和这么做是没有不同之处的
markLine(); // enter marking statevar ln = readLine(); // push old lineresetLine(); // enter initiate state若 reset buffer 还为空,则读入一行返回,此时即使长度为 1 的 buffer 充盈
if (lastLine == null)若 reset buffer 不为空且之前提交请求 lookback(backseek) 到上一个字符(keepLastLineOnce),
return readLine();
则返回上一个字符,把 boolean (这里可以视为一位二进制数值 i1)
true 减去 1(= false)否则就向前进一位,并且把已读数据加入 buffer
if (!keepLineOnce) {
return readLine();
} else {
keepLineOnce = false;
return lastLine;
}
(这里为了明确性我对控制流进行了展开)(删掉,之前是我搞混了 lastLine 和 readLine() 的值...)以后我要再写类似的解析程序,就会直接使用 mark/reset 了
GitHub
duangsuse-valid-projects/telegramscanner
Telegram Message stream scanner java library. Contribute to duangsuse-valid-projects/telegramscanner development by creating an account on GitHub.
duangsuse::Echo
Image to Bar3D... 😵???
注意,这里这个
var lum = ...; 是依据 RGB 颜色计算 Grayscale 灰度值的代码Gray_linear = 0.2126 × R + 0.7152 × G + 0.0722 × B
可是它还实际是被 255 减去了... 实际上这个值最大可能是 255(因为是一个色彩通道的色值)
duangsuse::Echo
顺便说一下为啥要进行 n 次,每次都要排序列表从 0 到 n - i -1 的项目,虽然我现在还没有证明为什么 bubble sort 输出的列表就一定是有序的的能力(归纳证明) 排序算法,就是给一个输入序列、一个测试函数『序(order)』,输出序列满足以下条件 forall i. list[i] `order` list[i+1] 比如 list=[3,2,1]; ord=(<) 简单的选择排序每次挑一个『最大』的元素出来(它满足 forall x in list. x <= it),复杂度是 O(n)…
#Java 修正:刚才看这个泛型通配符模拟的时候感觉有点不对劲,首先方法泛型应该只在很少的地方出现型变通配符,其次,
我模拟的时候发现这个实际算法逻辑
首先 xs 从 producer-consumer 模型来看它接受
我考虑了一下
这点是需要注意,我之前没有注意到,现在也及时修正了 #fix #Kotlin
其次,我从 Java 的 Collections API 看到了
我得使用通配符泛化一下(逆变声明)才能支持这个... (当然 Kotlin 里包装的就直接使用声明处型变了,不需要你操心它的型变性)
在此希望大家注意.... 不要搞混了 PECS 原则的实际含义
—
^1:
我模拟的时候发现这个实际算法逻辑
private static <T extends Comparable<T>> void propagateOnce(List<? super T> xs, final int ri);
中这个 xs :: List<capture<? super T>> 的使用 T get(int); 和 void set(int, T); 不对称首先 xs 从 producer-consumer 模型来看它接受
T 也生产 T,实际上就无法保证同时的类型安全(但是如果从这个方法的一个参数对象读另一个写,比如 copy 方法是没有问题的),所以它不应该有泛型协逆变(invariant)。我考虑了一下
T 是 Integer xs 是 List<Number> 的情况,PECS 原则 List<in Number> 也即 List<? super Number> 是可以安全地使用 set(int, T) 方法的(Integer 实例可以转换为超类 Number 的实例,虽然 Java 泛型擦除所以 List<T> 实际上运行时是 List[^1] 这个 raw type...),可是不可能同时安全使用 T get(int); (要将 Number 强制转换为 Integer,这是不合法的)这点是需要注意,我之前没有注意到,现在也及时修正了 #fix #Kotlin
其次,我从 Java 的 Collections API 看到了
sort 的方法签名public static <T extends Comparable<? super T>> void sort(List<T> list);
现在我把这个 <T extends Comparable<T>> 改为 <T extends Comparable<in T (? super T)>> ,显然 Comparable<Number> 的 int compare(T, T); 可以接受 T=Integer 作为比较输入我得使用通配符泛化一下(逆变声明)才能支持这个... (当然 Kotlin 里包装的就直接使用声明处型变了,不需要你操心它的型变性)
在此希望大家注意.... 不要搞混了 PECS 原则的实际含义
—
^1:
List<Object>, 和 List<?> 还是有区别的,因为这里的 ? 不能作为输入但作为输出可以强制转换成 Object,它像子类型系统里的 bottom type、Kotlin 的 Nothing,它是任何类型的子类型