qubit-function 0.8.1

Common functional programming type aliases for Rust, providing Java-style functional interfaces
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
# Predicate Design Analysis

## Overview

This document analyzes the design of Predicate (predicate) from the perspective of its essential semantics, exploring its main uses and core value, and discussing reasonable design approaches.

The core function of Predicate is **to determine whether a value satisfies specific conditions**, similar to Java's `Predicate<T>` interface and Rust standard library's `Fn(&T) -> bool`. This document will analyze in depth why many seemingly reasonable designs are actually over-engineered, and propose simplified solutions that better align with semantics.

---

## 1. The Essential Semantics of Predicate

### 1.1 What is a Predicate?

**Core semantics of Predicate (predicate)**:

> **Determine whether a value satisfies a certain condition, returning a boolean value. This is a pure "read-only judgment" operation that should have no side effects.**

This is similar to predicate logic in mathematics:
- **Condition judgment**: Read value properties and make true/false judgments
-**No side effects**: Do not modify the value being judged
-**Repeatability**: Same input should produce same result
-**Determinism**: Judgment logic should be deterministic and predictable

**Comparison with other functional abstractions**:

| Type | Input | Output | Modify Input? | Modify Self? | Typical Use |
|------|-------|--------|---------------|--------------|-------------|
| **Predicate** | `&T` | `bool` ||| Filtering, validation, condition judgment |
| **Consumer** | `&T` | `()` ||| Observation, logging, statistics, accumulation |
| **Function** | `&T` | `R` ||| Transformation, mapping, computation |

**Key insights**:
- Predicate's semantics is "judgment", and judgment itself should not change anything
- If a "predicate" changes state during judgment, it probably shouldn't be called a predicate

### 1.2 Main Uses of Predicate

| Use Case | Description | Example |
|----------|-------------|---------|
| **Filtering/Screening** | Used with `filter()` and other iterator methods | `vec.into_iter().filter(predicate)` |
| **Condition Validation** | Form validation, data validation | `validator.test(&user_input)` |
| **Logical Composition** | Building complex judgment conditions | `is_adult.and(&has_license)` |
| **Strategy Pattern** | Saving judgment logic as strategy | `rules.insert("age", predicate)` |
| **Configuration-driven** | Saving validation rules in configuration center | `config.get_validator("email")` |

### 1.3 Core Value of Predicate

**Temporary judgment vs. Saving logic**:

```rust
// ❌ No need for Predicate: temporary judgment once
if x > 0 && x % 2 == 0 {
    println!("positive and even");
}

// ✅ Need Predicate: save judgment logic for reuse
let is_valid = BoxPredicate::new(|x: &i32| *x > 0 && x % 2 == 0);
let result1 = values1.into_iter().filter(|x| is_valid.test(x));
let result2 = values2.into_iter().filter(|x| is_valid.test(x));
```

**The value of Predicate lies in**:
1. **Saving judgment logic**: Encapsulate judgment conditions as reusable objects
2. **Lazy execution**: Execute judgment only when needed
3. **Logical composition**: Build complex conditions through `and`, `or`, `not`
4. **Simplified interface**: Improve code readability as type constraints

---

## 2. Core Design Decisions

### 2.1 Why PredicateOnce is Not Needed? ❌

#### Semantic Contradiction

The essence of Predicate is "judgment", and judgment operations should naturally be **repeatable and side-effect-free**.

```rust
// 🤔 Is this reasonable?
let is_positive = BoxPredicateOnce::new(|x: &i32| *x > 0);
assert!(is_positive.test_once(&5));  // First judgment
// is_positive can't be used anymore! Why can "is positive" only be used once?
```

**Comparison with Consumer**:
- `ConsumerOnce` makes sense: consume a value, it's gone after consumption (like sending messages, closing resources)
- `PredicateOnce` is confusing: judge a value, why is the predicate gone after judgment?

#### Lack of Real Use Cases

The so-called "use cases" are all forced:

1. **Closure capturing non-cloneable resources** - This is not a typical Predicate scenario, more like special resource management
2. **Type system expressiveness** - Expressing for the sake of expressing, not real needs
3. **Lazy execution** - Using `FnOnce` closures directly is simpler

#### Blurred Boundary with PredicateMut

```rust
// PredicateMut can do everything PredicateOnce can do
let mut pred = BoxPredicateMut::new(|x: &i32| *x > 0);
pred.test_mut(&5);   // Can call once
pred.test_mut(&10);  // Can also call multiple times
pred.test_once(&15); // Finally consume it
```

**Conclusion**: `PredicateOnce` has extremely low value and is designed for "completeness", not from real needs. Should be **removed**.

---

### 2.2 Why PredicateMut is Not Needed? 🤔

#### Interior Mutability is Sufficient for All "State-requiring" Scenarios

All scenarios that seem to need `&mut self` can be implemented more elegantly using interior mutability:

**Scenario 1: Caching mechanism**

```rust
// ❌ Using PredicateMut
let mut cache = HashMap::new();
let mut pred = BoxPredicateMut::new(move |x: &i32| {
    *cache.entry(*x).or_insert_with(|| expensive(*x))
});
pred.test_mut(&5);  // User must write mut

// ✅ Using Predicate + RefCell
let cache = RefCell::new(HashMap::new());
let pred = BoxPredicate::new(move |x: &i32| {
    *cache.borrow_mut().entry(*x).or_insert_with(|| expensive(*x))
});
pred.test(&5);  // User doesn't need mut
```

**Scenario 2: Counter**

```rust
// ❌ Using PredicateMut
let mut count = 0;
let mut pred = BoxPredicateMut::new(move |x: &i32| {
    count += 1;
    *x > 0
});

// ✅ Using Predicate + Cell
let count = Cell::new(0);
let pred = BoxPredicate::new(move |x: &i32| {
    count.set(count.get() + 1);
    *x > 0
});
```

**Scenario 3: Thread-safe state**

```rust
// ❌ Using ArcPredicateMut
let counter = Arc::new(Mutex::new(0));
let mut pred = ArcPredicateMut::new(move |x: &i32| {
    let mut count = counter.lock().unwrap();
    *count += 1;
    *x > 0
});

// ✅ Using ArcPredicate + Mutex (same implementation)
let counter = Arc::new(Mutex::new(0));
let pred = ArcPredicate::new(move |x: &i32| {
    let mut count = counter.lock().unwrap();
    *count += 1;
    *x > 0
});
```

#### Why Interior Mutability is Better?

| Feature | PredicateMut (`&mut self`) | Predicate + RefCell (`&self`) |
|---------|---------------------------|-------------------------------|
| **User Code** | `let mut pred = ...` | `let pred = ...` |
| **Call Method** | `pred.test_mut(&x)` | `pred.test(&x)` |
| **Semantics** | "This predicate will change" ❌ | "This predicate is judgment" (internal optimization) ✅ |
| **Flexibility** | Cannot use in immutable context | Can use anywhere |
| **Implementation Complexity** | Needs additional trait | Unified using Predicate |

#### Comparison with Standard Library Design

Rust standard library extensively uses interior mutability to hide implementation details:

```rust
// Arc::clone internally modifies reference count, but interface is &self
pub fn clone(&self) -> Self {
    // Atomically increment reference count (interior mutability)
}

// RefCell provides interior mutability
let cell = RefCell::new(5);
let borrowed = cell.borrow_mut();  // &self → &mut T
```

**Conclusion**: `PredicateMut` is unnecessary complexity and should be **removed**. All state-requiring scenarios can be solved with interior mutability.

---

### 2.3 Simplified Core Design

Based on the above analysis, the Predicate module only needs:

```rust
/// Predicate - determines whether a value satisfies a condition
pub trait Predicate<T> {
    /// Test whether a value satisfies the condition
    ///
    /// Uses &self, won't change the predicate itself (from user perspective).
    /// If internal state is needed (like caching), use RefCell, Cell, or Mutex.
    fn test(&self, value: &T) -> bool;

    // Type conversion methods
    fn into_box(self) -> BoxPredicate<T> where ...;
    fn into_rc(self) -> RcPredicate<T> where ...;
    fn into_arc(self) -> ArcPredicate<T> where ...;
}
```

**Just this one trait!** Simple, clear, and semantically correct.

---

## 3. Implementation Approach Comparison

### Approach 1: Type Alias + Static Composition Methods

**Core idea**:

```rust
pub type Predicate<T> = Box<dyn Fn(&T) -> bool>;
pub type ArcPredicate<T> = Arc<dyn Fn(&T) -> bool + Send + Sync>;

pub struct Predicates;
impl Predicates {
    pub fn and<T>(first: ..., second: ...) -> Predicate<T> { ... }
    pub fn or<T>(first: ..., second: ...) -> Predicate<T> { ... }
}
```

**Advantages**:
- **Ultra-simple API**: Direct call `pred(&value)`
-**Zero mental burden**: Type aliases are completely transparent
-**Perfect integration with standard library**: Can be used directly with `filter` methods
-**Simple implementation**: Less code, easy to understand

**Disadvantages**:
- **Cannot extend**: Cannot add fields, implement traits
-**Low type distinction**: Equivalent to `Box<dyn Fn>`
-**Cannot implement method chaining**: Can only nest calls
-**Need to maintain multiple APIs**: Predicate, ArcPredicate, RcPredicate each have separate utility classes

**Applicable scenarios**: Rapid prototyping, simple applications, pursuing ultra-simple API

---

### Approach 2: Struct Encapsulation + Instance Methods

**Core idea**:

```rust
pub struct Predicate<T> {
    inner: Box<dyn Fn(&T) -> bool>,
    name: Option<String>,  // Can add metadata
}

impl<T> Predicate<T> {
    pub fn test(&self, value: &T) -> bool { ... }
    pub fn and(self, other: ...) -> Self { ... }  // Consumes self
    pub fn or(self, other: ...) -> Self { ... }
}

pub struct ArcPredicate<T> {
    inner: Arc<dyn Fn(&T) -> bool + Send + Sync>,
    name: Option<String>,
}
// Similar implementation...
```

**Advantages**:
- **Elegant method chaining**: `.and().or().not()` fluent calls
-**Strong extensibility**: Can add fields, implement traits
-**Type safety**: Independent types, clear semantics

**Disadvantages**:
- **Cannot call directly**: Must use `pred.test(&value)`
-**Need multiple independent implementations**: Predicate, ArcPredicate, RcPredicate code duplication
-**Ownership issues**: Box version method chaining consumes self, Arc version needs explicit clone

**Applicable scenarios**: Need metadata, need method chaining, object-oriented style

---

### Approach 3: Trait Abstraction + Multiple Implementations ⭐ (Recommended)

**Core idea**:

```rust
// 1. Unified Predicate trait (minimal)
pub trait Predicate<T> {
    fn test(&self, value: &T) -> bool;
    // Only test and into_* conversion methods, no logical composition
}

// 2. Implement Predicate for closures
impl<T, F> Predicate<T> for F where F: Fn(&T) -> bool {
    fn test(&self, value: &T) -> bool { self(value) }
}

// 3. Extension trait providing composition methods for closures
pub trait FnPredicateOps<T>: Fn(&T) -> bool {
    fn and<P>(self, other: P) -> BoxPredicate<T> { ... }
    fn or<P>(self, other: P) -> BoxPredicate<T> { ... }
}

// 4. Three specific implementations
pub struct BoxPredicate<T> { /* Box<dyn Fn> */ }
impl<T> BoxPredicate<T> {
    pub fn and<P>(self, other: P) -> BoxPredicate<T> { ... }  // Consumes self
}

pub struct ArcPredicate<T> { /* Arc<dyn Fn + Send + Sync> */ }
impl<T> ArcPredicate<T> {
    pub fn and(&self, other: &ArcPredicate<T>) -> ArcPredicate<T> { ... }  // Borrows &self
}

pub struct RcPredicate<T> { /* Rc<dyn Fn> */ }
impl<T> RcPredicate<T> {
    pub fn and(&self, other: &RcPredicate<T>) -> RcPredicate<T> { ... }  // Borrows &self
}
```

**Advantages**:
- **Unified trait interface**: All types implement the same `Predicate<T>`
-**Extremely clear semantics**: `BoxPredicate`, `ArcPredicate`, `RcPredicate` names are self-documenting
-**Complete ownership model**: Box (single), Arc (shared + thread-safe), Rc (shared + single-thread)
-**Type preservation**: `ArcPredicate.and()` returns `ArcPredicate`, maintaining cloneable characteristics
-**Elegant API**: Arc/Rc use `&self`, no need for explicit clone
-**Strongest extensibility**: Can add new types, fields, traits
-**Consistent with Rust standard library**: Similar to Box/Arc/Rc smart pointer design

**Disadvantages**:
- **Cannot call directly**: Still need `.test()`
-**Slightly higher learning cost**: Need to understand differences between three implementations
-**High implementation cost**: Need to implement separately for three structs

**Applicable scenarios**: Library development, large projects, long-term maintenance, multi-scenario support

---

## 4. Summary of Three Approaches

| Feature | Approach 1: Type Alias | Approach 2: Struct Encapsulation | Approach 3: Trait + Multi-impl ⭐ |
|:---|:---:|:---:|:---:|
| **Call Method** | `pred(&x)`| `pred.test(&x)` | `pred.test(&x)` |
| **Semantic Clarity** | 🟡 Medium | 🟢 Good | 🟢 **Excellent**|
| **Unified Interface** | ❌ Multiple independent APIs | ❌ Multiple independent structs |**Unified trait**|
| **Ownership Model** | Box + Arc (two) | Box + Arc (two) | Box + Arc + Rc (three) ✅ |
| **Method Chaining** | ❌ Can only nest | ✅ Supported |**Supported (with type preservation)**|
| **Extensibility** | ❌ Cannot extend | ✅ Extensible |**Highly extensible** |
| **Code Simplicity** |**Ultra-simple** | 🟡 Medium | 🟡 Slightly complex |
| **Learning Cost** |**Lowest** | 🟡 Medium | 🟡 Slightly high |
| **Maintenance Cost** | 🟡 Medium | 🟡 Medium |**Low (clear architecture)** |
| **Consistency with Standard Library** | 🟡 Medium | 🟡 Medium |**Perfect**|

---

## 5. Final Recommended Design

### 5.1 Core Architecture

```rust
// ============================================================================
// 1. Minimal Predicate trait
// ============================================================================

/// Predicate - determines whether a value satisfies a condition
pub trait Predicate<T> {
    /// Test whether a value satisfies the condition
    fn test(&self, value: &T) -> bool;

    // Type conversion methods
    fn into_box(self) -> BoxPredicate<T> where Self: Sized + 'static, T: 'static;
    fn into_rc(self) -> RcPredicate<T> where Self: Sized + 'static, T: 'static;
    fn into_arc(self) -> ArcPredicate<T> where Self: Sized + Send + Sync + 'static, T: Send + Sync + 'static;
}

// ============================================================================
// 2. Provide extension capabilities for closures
// ============================================================================

/// Implement Predicate trait for closures
impl<T, F> Predicate<T> for F where F: Fn(&T) -> bool {
    fn test(&self, value: &T) -> bool { self(value) }
    // ...
}

/// Extension trait providing composition methods for closures
pub trait FnPredicateOps<T>: Fn(&T) -> bool + Sized {
    fn and<P>(self, other: P) -> BoxPredicate<T> { ... }
    fn or<P>(self, other: P) -> BoxPredicate<T> { ... }
    fn not(self) -> BoxPredicate<T> { ... }
}

// ============================================================================
// 3. Three specific implementations
// ============================================================================

/// Box implementation - single ownership, consumes self
pub struct BoxPredicate<T> {
    function: Box<dyn Fn(&T) -> bool>,
    name: Option<String>,
}

impl<T> BoxPredicate<T> {
    pub fn and<P>(self, other: P) -> BoxPredicate<T> { ... }  // Consumes self
    pub fn or<P>(self, other: P) -> BoxPredicate<T> { ... }
    pub fn not(self) -> BoxPredicate<T> { ... }
}

/// Arc implementation - thread-safe sharing, borrows &self
pub struct ArcPredicate<T> {
    function: Arc<dyn Fn(&T) -> bool + Send + Sync>,
    name: Option<String>,
}

impl<T> ArcPredicate<T> {
    pub fn and(&self, other: &ArcPredicate<T>) -> ArcPredicate<T> { ... }  // Borrows &self
    pub fn or(&self, other: &ArcPredicate<T>) -> ArcPredicate<T> { ... }
    pub fn not(&self) -> ArcPredicate<T> { ... }

    // Provide to_* methods (doesn't consume self)
    pub fn to_box(&self) -> BoxPredicate<T> { ... }
    pub fn to_rc(&self) -> RcPredicate<T> { ... }
}

/// Rc implementation - single-thread sharing, borrows &self
pub struct RcPredicate<T> {
    function: Rc<dyn Fn(&T) -> bool>,
    name: Option<String>,
}

impl<T> RcPredicate<T> {
    pub fn and(&self, other: &RcPredicate<T>) -> RcPredicate<T> { ... }  // Borrows &self
    pub fn or(&self, other: &RcPredicate<T>) -> RcPredicate<T> { ... }
    pub fn not(&self) -> RcPredicate<T> { ... }

    // Provide to_* methods (doesn't consume self)
    pub fn to_box(&self) -> BoxPredicate<T> { ... }
}
```

### 5.2 Usage Examples

```rust
// Closures automatically implement Predicate
let is_positive = |x: &i32| *x > 0;
assert!(is_positive.test(&5));

// Closure composition returns BoxPredicate
let combined = is_positive.and(|x: &i32| x % 2 == 0);
assert!(combined.test(&4));

// BoxPredicate - one-time use
let pred = BoxPredicate::new(|x: &i32| *x > 0)
    .and(|x| x % 2 == 0);

// ArcPredicate - multi-thread sharing, no need for explicit clone
let arc_pred = ArcPredicate::new(|x: &i32| *x > 0);
let combined = arc_pred.and(&ArcPredicate::new(|x| x % 2 == 0));
assert!(arc_pred.test(&5));  // Original predicate still usable

// RcPredicate - single-thread reuse, better performance
let rc_pred = RcPredicate::new(|x: &i32| *x > 0);
let combined1 = rc_pred.and(&RcPredicate::new(|x| x % 2 == 0));
let combined2 = rc_pred.or(&RcPredicate::new(|x| *x > 100));

// Interior mutability for caching
use std::cell::RefCell;
let cache = RefCell::new(HashMap::new());
let cached = BoxPredicate::new(move |x: &i32| {
    *cache.borrow_mut().entry(*x).or_insert_with(|| expensive(*x))
});
cached.test(&5);  // No need for mut
```

### 5.3 Type Selection Guide

| Requirement | Recommended Type | Reason |
|-------------|------------------|---------|
| One-time use | `BoxPredicate` | Single ownership, no overhead |
| Multi-thread sharing | `ArcPredicate` | Thread-safe, cloneable |
| Single-thread reuse | `RcPredicate` | No atomic operations, better performance |
| Need internal state | Any type + RefCell/Cell/Mutex | Interior mutability |

---

## 6. Summary

### 6.1 Core Design Principles

1. **Predicate is pure judgment**: Doesn't modify input, doesn't modify self (semantically)
2. **Only need one Predicate trait**: Uses `&self`, simple and clear
3. **Remove PredicateOnce**: Violates semantics, lacks real scenarios
4. **Remove PredicateMut**: Interior mutability is completely sufficient
5. **Provide three implementations**: Box/Arc/Rc cover all ownership scenarios
6. **Type names are semantically clear**: BoxPredicate, ArcPredicate, RcPredicate

### 6.2 Why This Design is Best?

**Comparison with over-engineering**:

| | Over-engineering (Current) | Simplified Design (Recommended) |
|---|---|---|
| **Number of Traits** | 3 (Predicate, PredicateMut, PredicateOnce) | 1 (Predicate) ✅ |
| **Core Semantics** | Confusing (mutable, one-time) | Clear (pure judgment) ✅ |
| **User Mental Burden** | High (which one to use?) | Low (only one) ✅ |
| **State Management** | Needs `&mut self` | Interior mutability ✅ |
| **API Consistency** | Multiple methods (test, test_mut, test_once) | Unified test ✅ |

**Consistency with Consumer design**:

- Consumer **can** modify itself (accumulation, counting are core uses) → ConsumerMut is reasonable
- Predicate **should not** modify itself (pure judgment is core semantics) → PredicateMut is unreasonable

### 6.3 Final Conclusion

For a library project like `qubit-function`:

1. **Adopt Approach 3**: Trait + Multiple implementations
2. **Simplify to single Predicate trait**: Remove Mut and Once variants
3. **Provide three implementations**: BoxPredicate, ArcPredicate, RcPredicate
4. **Use interior mutability**: Use RefCell/Cell/Mutex when state is needed
5. **Document best practices**: Guide users on when to use which type

This design:
- **Simpler**: Only one core trait
-**More semantically correct**: Predicate is judgment, shouldn't "change"
-**More flexible**: No need for `mut`, can be used in more places
-**Consistent with Rust conventions**: Standard library extensively uses interior mutability patterns
-**Long-term maintainable**: Clear architecture, clear semantics

**This is a thoughtful, over-engineering-free, back-to-basics elegant solution.**